diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..240b349d3e8c725f1e5036092976fe014f69108c 100644
--- a/thirdparty/CMakeLists.txt
+++ b/thirdparty/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(KWSys)
diff --git a/thirdparty/KWSys/CMakeLists.txt b/thirdparty/KWSys/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..058c8f9ef4b292dae879db5cc061f10b0dfed2d7
--- /dev/null
+++ b/thirdparty/KWSys/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(KWSYS_NAMESPACE adios2sys)
+set(KWSYS_USE_DynamicLoader ON)
+set(KWSYS_BUILD_SHARED OFF)
+
+add_subdirectory(adios2sys)
diff --git a/thirdparty/KWSys/Readme.txt b/thirdparty/KWSys/Readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b85ba46a8578e56bdefa4ec57c174590a8e873df
--- /dev/null
+++ b/thirdparty/KWSys/Readme.txt
@@ -0,0 +1,4 @@
+This is a copy of the upstream KWSys repo located at
+https://gitlab.kitware.com/utils/kwsys.git.  Do not make changes directly to
+this repo but instead to the upstream repository.  Update this copy of KWSys by
+running the update.sh script.
diff --git a/thirdparty/KWSys/adios2sys/.clang-format b/thirdparty/KWSys/adios2sys/.clang-format
new file mode 100644
index 0000000000000000000000000000000000000000..a8bde417dd6f104e5c751e41bd730765909fbc26
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/.clang-format
@@ -0,0 +1,9 @@
+---
+# This configuration requires clang-format 3.8 or higher.
+BasedOnStyle: Mozilla
+AlignOperands: false
+AlwaysBreakAfterReturnType: None
+AlwaysBreakAfterDefinitionReturnType: None
+ColumnLimit: 79
+Standard: Cpp03
+...
diff --git a/thirdparty/KWSys/adios2sys/Base64.c b/thirdparty/KWSys/adios2sys/Base64.c
new file mode 100644
index 0000000000000000000000000000000000000000..37c3b8c40ad3a2802274dd30366a5633e4f21967
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Base64.c
@@ -0,0 +1,235 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Base64.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "Base64.h.in"
+#endif
+
+/*--------------------------------------------------------------------------*/
+static const unsigned char kwsysBase64EncodeTable[65] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "abcdefghijklmnopqrstuvwxyz"
+  "0123456789+/";
+
+/*--------------------------------------------------------------------------*/
+static const unsigned char kwsysBase64DecodeTable[256] = {
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37,
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
+  0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+  0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
+  0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  /*------------------------------------*/
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/*--------------------------------------------------------------------------*/
+static unsigned char kwsysBase64EncodeChar(int c)
+{
+  return kwsysBase64EncodeTable[(unsigned char)c];
+}
+
+/*--------------------------------------------------------------------------*/
+static unsigned char kwsysBase64DecodeChar(unsigned char c)
+{
+  return kwsysBase64DecodeTable[c];
+}
+
+/*--------------------------------------------------------------------------*/
+/* Encode 3 bytes into a 4 byte string. */
+void kwsysBase64_Encode3(const unsigned char* src, unsigned char* dest)
+{
+  dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
+  dest[1] =
+    kwsysBase64EncodeChar(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0F));
+  dest[2] =
+    kwsysBase64EncodeChar(((src[1] << 2) & 0x3C) | ((src[2] >> 6) & 0x03));
+  dest[3] = kwsysBase64EncodeChar(src[2] & 0x3F);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Encode 2 bytes into a 4 byte string. */
+void kwsysBase64_Encode2(const unsigned char* src, unsigned char* dest)
+{
+  dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
+  dest[1] =
+    kwsysBase64EncodeChar(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0F));
+  dest[2] = kwsysBase64EncodeChar(((src[1] << 2) & 0x3C));
+  dest[3] = '=';
+}
+
+/*--------------------------------------------------------------------------*/
+/* Encode 1 bytes into a 4 byte string. */
+void kwsysBase64_Encode1(const unsigned char* src, unsigned char* dest)
+{
+  dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
+  dest[1] = kwsysBase64EncodeChar(((src[0] << 4) & 0x30));
+  dest[2] = '=';
+  dest[3] = '=';
+}
+
+/*--------------------------------------------------------------------------*/
+/* Encode 'length' bytes from the input buffer and store the
+   encoded stream into the output buffer. Return the length of the encoded
+   buffer (output). Note that the output buffer must be allocated by the caller
+   (length * 1.5 should be a safe estimate).  If 'mark_end' is true than an
+   extra set of 4 bytes is added to the end of the stream if the input is a
+   multiple of 3 bytes.  These bytes are invalid chars and therefore they will
+   stop the decoder thus enabling the caller to decode a stream without
+   actually knowing how much data to expect (if the input is not a multiple of
+   3 bytes then the extra padding needed to complete the encode 4 bytes will
+   stop the decoding anyway).  */
+size_t kwsysBase64_Encode(const unsigned char* input, size_t length,
+                          unsigned char* output, int mark_end)
+{
+  const unsigned char* ptr = input;
+  const unsigned char* end = input + length;
+  unsigned char* optr = output;
+
+  /* Encode complete triplet */
+
+  while ((end - ptr) >= 3) {
+    kwsysBase64_Encode3(ptr, optr);
+    ptr += 3;
+    optr += 4;
+  }
+
+  /* Encodes a 2-byte ending into 3 bytes and 1 pad byte and writes. */
+
+  if (end - ptr == 2) {
+    kwsysBase64_Encode2(ptr, optr);
+    optr += 4;
+  }
+
+  /* Encodes a 1-byte ending into 2 bytes and 2 pad bytes */
+
+  else if (end - ptr == 1) {
+    kwsysBase64_Encode1(ptr, optr);
+    optr += 4;
+  }
+
+  /* Do we need to mark the end */
+
+  else if (mark_end) {
+    optr[0] = optr[1] = optr[2] = optr[3] = '=';
+    optr += 4;
+  }
+
+  return (size_t)(optr - output);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Decode 4 bytes into a 3 byte string. */
+int kwsysBase64_Decode3(const unsigned char* src, unsigned char* dest)
+{
+  unsigned char d0, d1, d2, d3;
+
+  d0 = kwsysBase64DecodeChar(src[0]);
+  d1 = kwsysBase64DecodeChar(src[1]);
+  d2 = kwsysBase64DecodeChar(src[2]);
+  d3 = kwsysBase64DecodeChar(src[3]);
+
+  /* Make sure all characters were valid */
+
+  if (d0 == 0xFF || d1 == 0xFF || d2 == 0xFF || d3 == 0xFF) {
+    return 0;
+  }
+
+  /* Decode the 3 bytes */
+
+  dest[0] = (unsigned char)(((d0 << 2) & 0xFC) | ((d1 >> 4) & 0x03));
+  dest[1] = (unsigned char)(((d1 << 4) & 0xF0) | ((d2 >> 2) & 0x0F));
+  dest[2] = (unsigned char)(((d2 << 6) & 0xC0) | ((d3 >> 0) & 0x3F));
+
+  /* Return the number of bytes actually decoded */
+
+  if (src[2] == '=') {
+    return 1;
+  }
+  if (src[3] == '=') {
+    return 2;
+  }
+  return 3;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Decode bytes from the input buffer and store the decoded stream
+   into the output buffer until 'length' bytes have been decoded.  Return the
+   real length of the decoded stream (which should be equal to 'length'). Note
+   that the output buffer must be allocated by the caller.  If
+   'max_input_length' is not null, then it specifies the number of encoded
+   bytes that should be at most read from the input buffer. In that case the
+   'length' parameter is ignored. This enables the caller to decode a stream
+   without actually knowing how much decoded data to expect (of course, the
+   buffer must be large enough). */
+size_t kwsysBase64_Decode(const unsigned char* input, size_t length,
+                          unsigned char* output, size_t max_input_length)
+{
+  const unsigned char* ptr = input;
+  unsigned char* optr = output;
+
+  /* Decode complete triplet */
+
+  if (max_input_length) {
+    const unsigned char* end = input + max_input_length;
+    while (ptr < end) {
+      int len = kwsysBase64_Decode3(ptr, optr);
+      optr += len;
+      if (len < 3) {
+        return (size_t)(optr - output);
+      }
+      ptr += 4;
+    }
+  } else {
+    unsigned char* oend = output + length;
+    while ((oend - optr) >= 3) {
+      int len = kwsysBase64_Decode3(ptr, optr);
+      optr += len;
+      if (len < 3) {
+        return (size_t)(optr - output);
+      }
+      ptr += 4;
+    }
+
+    /* Decode the last triplet */
+
+    if (oend - optr == 2) {
+      unsigned char temp[3];
+      int len = kwsysBase64_Decode3(ptr, temp);
+      if (len >= 2) {
+        optr[0] = temp[0];
+        optr[1] = temp[1];
+        optr += 2;
+      } else if (len > 0) {
+        optr[0] = temp[0];
+        optr += 1;
+      }
+    } else if (oend - optr == 1) {
+      unsigned char temp[3];
+      int len = kwsysBase64_Decode3(ptr, temp);
+      if (len > 0) {
+        optr[0] = temp[0];
+        optr += 1;
+      }
+    }
+  }
+
+  return (size_t)(optr - output);
+}
diff --git a/thirdparty/KWSys/adios2sys/Base64.h.in b/thirdparty/KWSys/adios2sys/Base64.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..35367574ae602a8f01bc361cb9d47659374f96c4
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Base64.h.in
@@ -0,0 +1,110 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Base64_h
+#define @KWSYS_NAMESPACE@_Base64_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+#include <stddef.h> /* size_t */
+
+/* Redefine all public interface symbol names to be in the proper
+   namespace.  These macros are used internally to kwsys only, and are
+   not visible to user code.  Use kwsysHeaderDump.pl to reproduce
+   these macros after making changes to the interface.  */
+#if !defined(KWSYS_NAMESPACE)
+#define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsysBase64 kwsys_ns(Base64)
+#define kwsysBase64_Decode kwsys_ns(Base64_Decode)
+#define kwsysBase64_Decode3 kwsys_ns(Base64_Decode3)
+#define kwsysBase64_Encode kwsys_ns(Base64_Encode)
+#define kwsysBase64_Encode1 kwsys_ns(Base64_Encode1)
+#define kwsysBase64_Encode2 kwsys_ns(Base64_Encode2)
+#define kwsysBase64_Encode3 kwsys_ns(Base64_Encode3)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Encode 3 bytes into a 4 byte string.
+ */
+kwsysEXPORT void kwsysBase64_Encode3(const unsigned char* src,
+                                     unsigned char* dest);
+
+/**
+ * Encode 2 bytes into a 4 byte string.
+ */
+kwsysEXPORT void kwsysBase64_Encode2(const unsigned char* src,
+                                     unsigned char* dest);
+
+/**
+ * Encode 1 bytes into a 4 byte string.
+ */
+kwsysEXPORT void kwsysBase64_Encode1(const unsigned char* src,
+                                     unsigned char* dest);
+
+/**
+ * Encode 'length' bytes from the input buffer and store the encoded
+ * stream into the output buffer. Return the length of the encoded
+ * buffer (output). Note that the output buffer must be allocated by
+ * the caller (length * 1.5 should be a safe estimate).  If 'mark_end'
+ * is true than an extra set of 4 bytes is added to the end of the
+ * stream if the input is a multiple of 3 bytes.  These bytes are
+ * invalid chars and therefore they will stop the decoder thus
+ * enabling the caller to decode a stream without actually knowing how
+ * much data to expect (if the input is not a multiple of 3 bytes then
+ * the extra padding needed to complete the encode 4 bytes will stop
+ * the decoding anyway).
+ */
+kwsysEXPORT size_t kwsysBase64_Encode(const unsigned char* input,
+                                      size_t length, unsigned char* output,
+                                      int mark_end);
+
+/**
+ * Decode 4 bytes into a 3 byte string.  Returns the number of bytes
+ * actually decoded.
+ */
+kwsysEXPORT int kwsysBase64_Decode3(const unsigned char* src,
+                                    unsigned char* dest);
+
+/**
+ * Decode bytes from the input buffer and store the decoded stream
+ * into the output buffer until 'length' bytes have been decoded.
+ * Return the real length of the decoded stream (which should be equal
+ * to 'length'). Note that the output buffer must be allocated by the
+ * caller.  If 'max_input_length' is not null, then it specifies the
+ * number of encoded bytes that should be at most read from the input
+ * buffer. In that case the 'length' parameter is ignored. This
+ * enables the caller to decode a stream without actually knowing how
+ * much decoded data to expect (of course, the buffer must be large
+ * enough).
+ */
+kwsysEXPORT size_t kwsysBase64_Decode(const unsigned char* input,
+                                      size_t length, unsigned char* output,
+                                      size_t max_input_length);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+   Otherwise, undefine them to keep the namespace clean.  */
+#if !defined(KWSYS_NAMESPACE)
+#undef kwsys_ns
+#undef kwsysEXPORT
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#undef kwsysBase64
+#undef kwsysBase64_Decode
+#undef kwsysBase64_Decode3
+#undef kwsysBase64_Encode
+#undef kwsysBase64_Encode1
+#undef kwsysBase64_Encode2
+#undef kwsysBase64_Encode3
+#endif
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/CMakeLists.txt b/thirdparty/KWSys/adios2sys/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e15b49e42638dad201c022544633bf88ecb74093
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/CMakeLists.txt
@@ -0,0 +1,1076 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
+
+# The Kitware System Library is intended to be included in other
+# projects.  It is completely configurable in that the library's
+# namespace can be configured and the components that are included can
+# be selected invididually.
+
+# Typical usage is to import the kwsys directory tree into a
+# subdirectory under a parent project and enable the classes that will
+# be used.  All classes are disabled by default.  The CMake listfile
+# above this one configures the library as follows:
+#
+#  SET(KWSYS_NAMESPACE foosys)
+#  SET(KWSYS_USE_Directory 1)    # Enable Directory class.
+#  SUBDIRS(kwsys)
+#
+# Optional settings are as follows:
+#
+#  KWSYS_HEADER_ROOT = The directory into which to generate the kwsys headers.
+#                      A directory called "${KWSYS_NAMESPACE}" will be
+#                      created under this root directory to hold the files.
+#
+#    Example:
+#
+#      SET(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR})
+#      INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR})
+#
+# Optional settings to setup install rules are as follows:
+#
+#  KWSYS_INSTALL_BIN_DIR     = The installation target directories into
+#  KWSYS_INSTALL_LIB_DIR       which the libraries and headers from
+#  KWSYS_INSTALL_INCLUDE_DIR   kwsys should be installed by a "make install".
+#                              The values should be specified relative to
+#                              the installation prefix and NOT start with '/'.
+#  KWSYS_INSTALL_DOC_DIR     = The installation target directory for documentation
+#                              such as copyright information.
+#
+#  KWSYS_INSTALL_COMPONENT_NAME_RUNTIME     = Name of runtime and development
+#  KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT   installation components.
+#                                             If not given the install rules
+#                                             will not be in any component.
+#
+#  KWSYS_INSTALL_EXPORT_NAME = The EXPORT option value for install(TARGETS) calls.
+#
+#    Example:
+#
+#      SET(KWSYS_INSTALL_BIN_DIR bin)
+#      SET(KWSYS_INSTALL_LIB_DIR lib)
+#      SET(KWSYS_INSTALL_INCLUDE_DIR include)
+#      SET(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime)
+#      SET(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development)
+
+# Once configured, kwsys should be used as follows from C or C++ code:
+#
+#  #include <foosys/Directory.hxx>
+#   ...
+#  foosys::Directory directory;
+#
+
+# NOTE: This library is intended for internal use by Kitware-driven
+# projects.  In order to keep it simple no attempt will be made to
+# maintain backward compatibility when changes are made to KWSys.
+# When an incompatible change is made Kitware's projects that use
+# KWSys will be fixed, but no notification will necessarily be sent to
+# any outside mailing list and no documentation of the change will be
+# written.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3 FATAL_ERROR)
+FOREACH(p
+    CMP0025 # CMake 3.0, Compiler id for Apple Clang is now AppleClang.
+    CMP0048 # CMake 3.0, Let the project command manage version variables.
+    CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature.
+    CMP0063 # CMake 3.3, Honor visibility properties for all target types.
+    )
+  IF(POLICY ${p})
+    CMAKE_POLICY(SET ${p} NEW)
+  ENDIF()
+ENDFOREACH()
+SET(CMAKE_LEGACY_CYGWIN_WIN32 0)
+
+#-----------------------------------------------------------------------------
+# If a namespace is not specified, use "kwsys" and enable testing.
+# This should be the case only when kwsys is not included inside
+# another project and is being tested.
+IF(NOT KWSYS_NAMESPACE)
+  SET(KWSYS_NAMESPACE "kwsys")
+  SET(KWSYS_STANDALONE 1)
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# The project name is that of the specified namespace.
+PROJECT(${KWSYS_NAMESPACE})
+
+# Tell CMake how to follow dependencies of sources in this directory.
+SET_PROPERTY(DIRECTORY
+  PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
+  "KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>"
+  )
+
+# Select library components.
+IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
+  SET(KWSYS_ENABLE_C 1)
+  # Enable all components.
+  SET(KWSYS_USE_Base64 1)
+  SET(KWSYS_USE_Directory 1)
+  SET(KWSYS_USE_DynamicLoader 1)
+  SET(KWSYS_USE_Encoding 1)
+  SET(KWSYS_USE_Glob 1)
+  SET(KWSYS_USE_MD5 1)
+  SET(KWSYS_USE_Process 1)
+  SET(KWSYS_USE_RegularExpression 1)
+  SET(KWSYS_USE_System 1)
+  SET(KWSYS_USE_SystemTools 1)
+  SET(KWSYS_USE_CommandLineArguments 1)
+  SET(KWSYS_USE_Terminal 1)
+  SET(KWSYS_USE_IOStream 1)
+  SET(KWSYS_USE_FStream 1)
+  SET(KWSYS_USE_String 1)
+  SET(KWSYS_USE_SystemInformation 1)
+  SET(KWSYS_USE_ConsoleBuf 1)
+ENDIF()
+
+# Enforce component dependencies.
+IF(KWSYS_USE_SystemTools)
+  SET(KWSYS_USE_Directory 1)
+  SET(KWSYS_USE_FStream 1)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_Glob)
+  SET(KWSYS_USE_Directory 1)
+  SET(KWSYS_USE_SystemTools 1)
+  SET(KWSYS_USE_RegularExpression 1)
+  SET(KWSYS_USE_FStream 1)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_Process)
+  SET(KWSYS_USE_System 1)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_SystemInformation)
+  SET(KWSYS_USE_Process 1)
+ENDIF()
+IF(KWSYS_USE_System)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_Directory)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_FStream)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
+IF(KWSYS_USE_ConsoleBuf)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
+
+# Setup the large file support default.
+IF(KWSYS_LFS_DISABLE)
+  SET(KWSYS_LFS_REQUESTED 0)
+ELSE()
+  SET(KWSYS_LFS_REQUESTED 1)
+ENDIF()
+
+# Specify default 8 bit encoding for Windows
+IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE)
+  SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP)
+ENDIF()
+
+# Enable testing if building standalone.
+IF(KWSYS_STANDALONE)
+  INCLUDE(Dart)
+  MARK_AS_ADVANCED(BUILD_TESTING DART_ROOT TCL_TCLSH)
+  IF(BUILD_TESTING)
+    ENABLE_TESTING()
+  ENDIF()
+ENDIF()
+
+# Include helper macros.
+INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake)
+INCLUDE(CheckTypeSize)
+
+# Do full dependency headers.
+INCLUDE_REGULAR_EXPRESSION("^.*$")
+
+# Use new KWSYS_INSTALL_*_DIR variable names to control installation.
+# Take defaults from the old names.  Note that there was no old name
+# for the bin dir, so we take the old lib dir name so DLLs will be
+# installed in a compatible way for old code.
+IF(NOT KWSYS_INSTALL_INCLUDE_DIR)
+  STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR
+    "${KWSYS_HEADER_INSTALL_DIR}")
+ENDIF()
+IF(NOT KWSYS_INSTALL_LIB_DIR)
+  STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR
+    "${KWSYS_LIBRARY_INSTALL_DIR}")
+ENDIF()
+IF(NOT KWSYS_INSTALL_BIN_DIR)
+  STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR
+    "${KWSYS_LIBRARY_INSTALL_DIR}")
+ENDIF()
+
+# Setup header install rules.
+SET(KWSYS_INSTALL_INCLUDE_OPTIONS)
+IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
+  SET(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS}
+    COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
+    )
+ENDIF()
+
+# Setup library install rules.
+SET(KWSYS_INSTALL_LIBRARY_RULE)
+IF(KWSYS_INSTALL_LIB_DIR)
+  IF(KWSYS_INSTALL_EXPORT_NAME)
+    LIST(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME})
+  ENDIF()
+  # Install the shared library to the lib directory.
+  SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+    LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR}
+    )
+  # Assign the shared library to the runtime component.
+  IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+    SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+      COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+      )
+  ENDIF()
+
+  # Install the archive to the lib directory.
+  SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+    ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR}
+    )
+  # Assign the archive to the development component.
+  IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
+    SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+      COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
+      )
+  ENDIF()
+ENDIF()
+IF(KWSYS_INSTALL_BIN_DIR)
+  # Install the runtime library to the bin directory.
+  SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+    RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR}
+    )
+  # Assign the runtime library to the runtime component.
+  IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+    SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
+      COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+      )
+  ENDIF()
+ENDIF()
+
+# Do not support old KWSYS_*a_INSTALL_DIR variable names.
+SET(KWSYS_HEADER_INSTALL_DIR)
+SET(KWSYS_LIBRARY_INSTALL_DIR)
+
+# Generated source files will need this header.
+STRING(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}"
+  KWSYS_IN_SOURCE_BUILD)
+IF(NOT KWSYS_IN_SOURCE_BUILD)
+  CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsysPrivate.h
+    ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE)
+ENDIF()
+
+# Select plugin module file name convention.
+IF(NOT KWSYS_DynamicLoader_PREFIX)
+  SET(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX})
+ENDIF()
+IF(NOT KWSYS_DynamicLoader_SUFFIX)
+  SET(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX})
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# We require ANSI support from the C compiler.  Add any needed flags.
+IF(CMAKE_ANSI_CFLAGS)
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}")
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Adjust compiler flags for some platforms.
+IF(NOT CMAKE_COMPILER_IS_GNUCXX)
+  IF(CMAKE_SYSTEM MATCHES "OSF1-V.*")
+    STRING(REGEX MATCH "-timplicit_local"
+      KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}")
+    STRING(REGEX MATCH "-no_implicit_include"
+      KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}")
+    IF(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL)
+      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local")
+    ENDIF()
+    IF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE)
+      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include")
+    ENDIF()
+  ENDIF()
+  IF(CMAKE_SYSTEM MATCHES "HP-UX")
+    SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p")
+    IF(CMAKE_CXX_COMPILER_ID MATCHES "HP")
+      # it is known that version 3.85 fails and 6.25 works without these flags
+      IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4)
+        # use new C++ library and improved template support
+        SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98")
+      ENDIF()
+    ENDIF()
+  ENDIF()
+ENDIF()
+IF(KWSYS_STANDALONE)
+  IF(CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
+    IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
+      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
+    ELSE()
+      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4")
+    ENDIF()
+  ENDIF()
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Configure Large File Support.
+KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CSTDIO
+  "Checking whether header cstdio is available" DIRECT)
+SET(KWSYS_LFS_AVAILABLE 0)
+IF(KWSYS_LFS_REQUESTED)
+  # Large File Support is requested.
+  SET(KWSYS_LFS_REQUESTED 1)
+
+  # Check for large file support.
+  SET(KWSYS_PLATFORM_CXX_TEST_DEFINES
+    -DKWSYS_CXX_HAS_CSTDIO=${KWSYS_CXX_HAS_CSTDIO})
+  KWSYS_PLATFORM_CXX_TEST_RUN(KWSYS_LFS_WORKS
+    "Checking for Large File Support" DIRECT)
+  SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
+
+  IF(KWSYS_LFS_WORKS)
+    SET(KWSYS_LFS_AVAILABLE 1)
+  ENDIF()
+ELSE()
+  # Large File Support is not requested.
+  SET(KWSYS_LFS_REQUESTED 0)
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Configure the standard library header wrappers based on compiler's
+# capabilities and parent project's request.  Enforce 0/1 as only
+# possible values for configuration into Configure.hxx.
+
+# Check existence and uniqueness of long long and __int64.
+KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_LONG_LONG
+  "Checking whether C++ compiler has 'long long'" DIRECT)
+KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS___INT64
+  "Checking whether C++ compiler has '__int64'" DIRECT)
+IF(KWSYS_CXX_HAS___INT64)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_AND___INT64
+    "Checking whether long and __int64 are the same type" DIRECT)
+  IF(KWSYS_CXX_HAS_LONG_LONG)
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_LONG_AND___INT64
+      "Checking whether long long and __int64 are the same type" DIRECT)
+  ENDIF()
+ENDIF()
+
+# Enable the "long long" type if it is available.  It is standard in
+# C99 and C++03 but not in earlier standards.
+IF(KWSYS_CXX_HAS_LONG_LONG)
+  SET(KWSYS_USE_LONG_LONG 1)
+ELSE()
+  SET(KWSYS_USE_LONG_LONG 0)
+ENDIF()
+
+# Enable the "__int64" type if it is available and unique.  It is not
+# standard.
+SET(KWSYS_USE___INT64 0)
+IF(KWSYS_CXX_HAS___INT64)
+  IF(NOT KWSYS_CXX_SAME_LONG_AND___INT64)
+    IF(NOT KWSYS_CXX_SAME_LONG_LONG_AND___INT64)
+      SET(KWSYS_USE___INT64 1)
+    ENDIF()
+  ENDIF()
+ENDIF()
+
+IF(KWSYS_USE_Encoding)
+  # Look for type size helper macros.
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING
+    "Checking whether wstring is available" DIRECT)
+ENDIF()
+
+IF(KWSYS_USE_IOStream)
+  # Determine whether iostreams support long long.
+  IF(KWSYS_CXX_HAS_LONG_LONG)
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+      "Checking if istream supports long long" DIRECT)
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+      "Checking if ostream supports long long" DIRECT)
+  ELSE()
+    SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0)
+    SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0)
+  ENDIF()
+  IF(KWSYS_CXX_HAS___INT64)
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM___INT64
+      "Checking if istream supports __int64" DIRECT)
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM___INT64
+      "Checking if ostream supports __int64" DIRECT)
+  ELSE()
+    SET(KWSYS_IOS_HAS_ISTREAM___INT64 0)
+    SET(KWSYS_IOS_HAS_OSTREAM___INT64 0)
+  ENDIF()
+ENDIF()
+
+IF(KWSYS_NAMESPACE MATCHES "^kwsys$")
+  SET(KWSYS_NAME_IS_KWSYS 1)
+ELSE()
+  SET(KWSYS_NAME_IS_KWSYS 0)
+ENDIF()
+
+# Choose default shared/static build if not specified.
+IF(KWSYS_BUILD_SHARED MATCHES "^KWSYS_BUILD_SHARED$")
+  SET(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS})
+ENDIF()
+
+IF(KWSYS_BUILD_SHARED)
+  SET(KWSYS_BUILD_SHARED 1)
+  SET(KWSYS_LIBRARY_TYPE SHARED)
+ELSE()
+  SET(KWSYS_BUILD_SHARED 0)
+  SET(KWSYS_LIBRARY_TYPE STATIC)
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Configure some implementation details.
+
+KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T
+  "Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT)
+KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T
+  "Checking whether C compiler has ssize_t in unistd.h" DIRECT)
+SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES
+  COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T}"
+  )
+
+IF(KWSYS_USE_DynamicLoader)
+  GET_PROPERTY(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
+  IF(KWSYS_SUPPORTS_SHARED_LIBS)
+    SET(KWSYS_SUPPORTS_SHARED_LIBS 1)
+  ELSE()
+    SET(KWSYS_SUPPORTS_SHARED_LIBS 0)
+  ENDIF()
+  SET_PROPERTY(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+    KWSYS_SUPPORTS_SHARED_LIBS=${KWSYS_SUPPORTS_SHARED_LIBS})
+ENDIF()
+
+IF(KWSYS_USE_SystemTools)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV
+    "Checking whether CXX compiler has setenv" DIRECT)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV
+    "Checking whether CXX compiler has unsetenv" DIRECT)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
+    "Checking whether CXX compiler has environ in stdlib.h" DIRECT)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMES
+    "Checking whether CXX compiler has utimes" DIRECT)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMENSAT
+    "Checking whether CXX compiler has utimensat" DIRECT)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIM
+    "Checking whether CXX compiler struct stat has st_mtim member" DIRECT)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+    "Checking whether CXX compiler struct stat has st_mtimespec member" DIRECT)
+  SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+    KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV}
+    KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV}
+    KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H}
+    KWSYS_CXX_HAS_UTIMES=${KWSYS_CXX_HAS_UTIMES}
+    KWSYS_CXX_HAS_UTIMENSAT=${KWSYS_CXX_HAS_UTIMENSAT}
+    KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM}
+    KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC}
+    )
+ENDIF()
+
+IF(KWSYS_USE_SystemInformation)
+  SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+    COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P})
+  IF(NOT CYGWIN)
+    INCLUDE(CheckIncludeFiles)
+    CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H)
+    IF(KWSYS_SYS_HAS_IFADDRS_H)
+      SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+        COMPILE_DEFINITIONS KWSYS_SYS_HAS_IFADDRS_H=1)
+    ENDIF()
+  ENDIF()
+  IF(WIN32)
+    INCLUDE(CheckSymbolExists)
+    SET(CMAKE_REQUIRED_LIBRARIES Psapi)
+    CHECK_SYMBOL_EXISTS(GetProcessMemoryInfo "windows.h;psapi.h" KWSYS_SYS_HAS_PSAPI)
+    UNSET(CMAKE_REQUIRED_LIBRARIES)
+    IF(KWSYS_SYS_HAS_PSAPI)
+      SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+        COMPILE_DEFINITIONS KWSYS_SYS_HAS_PSAPI=1)
+      IF(MSVC70 OR MSVC71)
+        # Suppress LNK4089: all references to 'PSAPI.DLL' discarded by /OPT:REF
+        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089")
+      ENDIF()
+    ENDIF()
+  ENDIF()
+  IF(CMAKE_SYSTEM MATCHES "HP-UX")
+    CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H)
+    IF(KWSYS_SYS_HAS_MPCTL_H)
+      SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+        COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1)
+    ENDIF()
+  ENDIF()
+  IF(CMAKE_SYSTEM MATCHES "BSD")
+    CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H)
+    IF(KWSYS_SYS_HAS_MACHINE_CPU_H)
+      SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+        COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1)
+    ENDIF()
+  ENDIF()
+  IF(KWSYS_LFS_AVAILABLE AND NOT KWSYS_LFS_DISABLE)
+    SET(KWSYS_PLATFORM_CXX_TEST_DEFINES -DKWSYS_HAS_LFS=1)
+  ENDIF()
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64
+    "Checking whether CXX compiler has rlimit64" DIRECT)
+  SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
+  IF(KWSYS_CXX_HAS_RLIMIT64)
+    SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1)
+  ENDIF()
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOL
+    "Checking whether CXX compiler has atol" DIRECT)
+  IF(KWSYS_CXX_HAS_ATOL)
+    SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1)
+  ENDIF()
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOLL
+    "Checking whether CXX compiler has atoll" DIRECT)
+  IF(KWSYS_CXX_HAS_ATOLL)
+    SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1)
+  ENDIF()
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS__ATOI64
+    "Checking whether CXX compiler has _atoi64" DIRECT)
+  IF(KWSYS_CXX_HAS__ATOI64)
+    SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1)
+  ENDIF()
+  IF(UNIX)
+    INCLUDE(CheckIncludeFileCXX)
+    # check for simple stack trace
+    # usually it's in libc but on FreeBSD
+    # it's in libexecinfo
+    FIND_LIBRARY(EXECINFO_LIB "execinfo")
+    MARK_AS_ADVANCED(EXECINFO_LIB)
+    IF (NOT EXECINFO_LIB)
+      SET(EXECINFO_LIB "")
+    ENDIF()
+    CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH)
+    IF (KWSYS_CXX_HAS_EXECINFOH)
+      # we have the backtrace header check if it
+      # can be used  with this compiler
+      SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB})
+      KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE
+         "Checking whether backtrace works with this C++ compiler" DIRECT)
+      SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
+      IF (KWSYS_CXX_HAS_BACKTRACE)
+        # backtrace is supported by this system and compiler.
+        # now check for the more advanced capabilities.
+        SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+          COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1)
+        # check for symbol lookup using dladdr
+        CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH)
+        IF (KWSYS_CXX_HAS_DLFCNH)
+          # we have symbol lookup libraries and headers
+          # check if they can be used with this compiler
+          SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS})
+            KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR
+            "Checking whether dladdr works with this C++ compiler" DIRECT)
+          SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
+          IF (KWSYS_CXX_HAS_DLADDR)
+            # symbol lookup is supported by this system
+            # and compiler.
+            SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+              COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1)
+          ENDIF()
+        ENDIF()
+        # c++ demangling support
+        # check for cxxabi headers
+        CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH)
+        IF (KWSYS_CXX_HAS_CXXABIH)
+          # check if cxxabi can be used with this
+          # system and compiler.
+          KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI
+            "Checking whether cxxabi works with this C++ compiler" DIRECT)
+          IF (KWSYS_CXX_HAS_CXXABI)
+            # c++ demangle using cxxabi is supported with
+            # this system and compiler
+            SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+              COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1)
+          ENDIF()
+        ENDIF()
+        # basic backtrace works better with release build
+        # don't bother with advanced features for release
+        SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+          COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
+        SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+          COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
+      ENDIF()
+    ENDIF()
+  ENDIF()
+  IF(BORLAND)
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM
+      "Checking whether Borland CXX compiler supports assembler instructions" DIRECT)
+    IF(KWSYS_CXX_HAS_BORLAND_ASM)
+      SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+        COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM=1)
+      KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM_CPUID
+        "Checking whether Borland CXX compiler supports CPUID assembler instruction" DIRECT)
+      IF(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
+        SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+          COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM_CPUID=1)
+      ENDIF()
+    ENDIF()
+  ENDIF()
+  IF(KWSYS_USE___INT64)
+    SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_USE___INT64=1)
+  ENDIF()
+  IF(KWSYS_USE_LONG_LONG)
+    SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=1)
+  ENDIF()
+  IF(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
+    SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM_LONG_LONG=1)
+  ENDIF()
+  IF(KWSYS_IOS_HAS_OSTREAM___INT64)
+    SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1)
+  ENDIF()
+  IF(KWSYS_BUILD_SHARED)
+    SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+      COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1)
+  ENDIF()
+
+  IF(UNIX AND NOT CYGWIN)
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG
+      "Checking whether CXX compiler has getloadavg" DIRECT)
+    IF(KWSYS_CXX_HAS_GETLOADAVG)
+      SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
+        COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1)
+    ENDIF()
+  ENDIF()
+ENDIF()
+
+IF(KWSYS_USE_FStream)
+  KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H
+    "Checking whether <ext/stdio_filebuf.h> is available" DIRECT)
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Choose a directory for the generated headers.
+IF(NOT KWSYS_HEADER_ROOT)
+  SET(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}")
+ENDIF()
+SET(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}")
+INCLUDE_DIRECTORIES(${KWSYS_HEADER_ROOT})
+
+#-----------------------------------------------------------------------------
+IF(KWSYS_INSTALL_DOC_DIR)
+  # Assign the license to the runtime component since it must be
+  # distributed with binary forms of this software.
+  IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
+    SET(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS}
+      COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
+      )
+  ENDIF()
+
+  # Install the license under the documentation directory.
+  INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt
+    DESTINATION ${KWSYS_INSTALL_DOC_DIR}/${KWSYS_NAMESPACE}
+    ${KWSYS_INSTALL_LICENSE_OPTIONS})
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Build a list of classes and headers we need to implement the
+# selected components.  Initialize with required components.
+SET(KWSYS_CLASSES)
+SET(KWSYS_H_FILES Configure SharedForward)
+SET(KWSYS_HXX_FILES Configure String
+  hashtable hash_fun hash_map hash_set
+  )
+
+# Add selected C++ classes.
+SET(cppclasses
+  Directory DynamicLoader Encoding Glob RegularExpression SystemTools
+  CommandLineArguments IOStream FStream SystemInformation ConsoleBuf
+  )
+FOREACH(cpp ${cppclasses})
+  IF(KWSYS_USE_${cpp})
+    # Use the corresponding class.
+    SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp})
+
+    # Load component-specific CMake code.
+    IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
+      INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
+    ENDIF()
+  ENDIF()
+ENDFOREACH()
+
+# Add selected C components.
+FOREACH(c
+    Process Base64 Encoding MD5 Terminal System String
+    )
+  IF(KWSYS_USE_${c})
+    # Use the corresponding header file.
+    SET(KWSYS_H_FILES ${KWSYS_H_FILES} ${c})
+
+    # Load component-specific CMake code.
+    IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
+      INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
+    ENDIF()
+  ENDIF()
+ENDFOREACH()
+
+#-----------------------------------------------------------------------------
+# Build a list of sources for the library based on components that are
+# included.
+SET(KWSYS_C_SRCS)
+SET(KWSYS_CXX_SRCS)
+
+# Add the proper sources for this platform's Process implementation.
+IF(KWSYS_USE_Process)
+  IF(NOT UNIX)
+    # Use the Windows implementation.
+    SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c)
+  ELSE()
+    # Use the UNIX implementation.
+    SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c)
+  ENDIF()
+ENDIF()
+
+# Add selected C sources.
+FOREACH(c Base64 Encoding MD5 Terminal System String)
+  IF(KWSYS_USE_${c})
+    IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c)
+      LIST(APPEND KWSYS_C_SRCS ${c}C.c)
+    ELSE()
+      LIST(APPEND KWSYS_C_SRCS ${c}.c)
+    ENDIF()
+  ENDIF()
+ENDFOREACH()
+
+# Configure headers of C++ classes and construct the list of sources.
+FOREACH(c ${KWSYS_CLASSES})
+  # Add this source to the list of source files for the library.
+  IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx)
+    LIST(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx)
+  ELSEIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx)
+    LIST(APPEND KWSYS_CXX_SRCS ${c}.cxx)
+  ENDIF()
+
+  # Configure the header for this class.
+  CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx
+                 @ONLY IMMEDIATE)
+  SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx)
+
+  # Create an install target for the header.
+  IF(KWSYS_INSTALL_INCLUDE_DIR)
+    INSTALL(FILES ${KWSYS_HEADER_DIR}/${c}.hxx
+      DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+      ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+  ENDIF()
+ENDFOREACH()
+
+# Configure C headers.
+FOREACH(h ${KWSYS_H_FILES})
+  # Configure the header into the given directory.
+  CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h
+                 @ONLY IMMEDIATE)
+  SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h)
+
+  # Create an install target for the header.
+  IF(KWSYS_INSTALL_INCLUDE_DIR)
+    INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.h
+      DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+      ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+  ENDIF()
+ENDFOREACH()
+
+# Configure other C++ headers.
+FOREACH(h ${KWSYS_HXX_FILES})
+  # Configure the header into the given directory.
+  CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx
+                 @ONLY IMMEDIATE)
+  SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx)
+
+  # Create an install target for the header.
+  IF(KWSYS_INSTALL_INCLUDE_DIR)
+    INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.hxx
+      DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
+      ${KWSYS_INSTALL_INCLUDE_OPTIONS})
+  ENDIF()
+ENDFOREACH()
+
+#-----------------------------------------------------------------------------
+# Add the library with the configured name and list of sources.
+IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS)
+  ADD_LIBRARY(${KWSYS_NAMESPACE} ${KWSYS_LIBRARY_TYPE}
+    ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS})
+  SET_PROPERTY(TARGET ${KWSYS_NAMESPACE} PROPERTY C_INCLUDE_WHAT_YOU_USE "")
+  SET_PROPERTY(TARGET ${KWSYS_NAMESPACE} PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
+  SET_PROPERTY(TARGET ${KWSYS_NAMESPACE} PROPERTY LABELS ${KWSYS_LABELS_LIB})
+  IF(KWSYS_USE_DynamicLoader)
+    IF(UNIX)
+      TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${CMAKE_DL_LIBS})
+    ENDIF()
+  ENDIF()
+
+  IF(KWSYS_USE_SystemInformation)
+    IF(WIN32)
+      TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ws2_32)
+      IF(KWSYS_SYS_HAS_PSAPI)
+        TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} Psapi)
+      ENDIF()
+    ELSEIF(UNIX)
+      IF (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE)
+        # backtrace on FreeBSD is not in libc
+        TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${EXECINFO_LIB})
+      ENDIF()
+      IF (KWSYS_CXX_HAS_DLADDR)
+        # for symbol lookup using dladdr
+        TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${CMAKE_DL_LIBS})
+      ENDIF()
+      IF (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+        TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} socket)
+      ENDIF()
+    ENDIF()
+  ENDIF()
+
+  # Apply user-defined target properties to the library.
+  IF(KWSYS_PROPERTIES_CXX)
+    SET_TARGET_PROPERTIES(${KWSYS_NAMESPACE} PROPERTIES
+      ${KWSYS_PROPERTIES_CXX}
+      )
+  ENDIF()
+
+  # Create an install target for the library.
+  IF(KWSYS_INSTALL_LIBRARY_RULE)
+    INSTALL(TARGETS ${KWSYS_NAMESPACE} ${KWSYS_INSTALL_LIBRARY_RULE})
+  ENDIF()
+ENDIF()
+
+# Add a C-only library if requested.
+IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS)
+  ADD_LIBRARY(${KWSYS_NAMESPACE}_c ${KWSYS_LIBRARY_TYPE} ${KWSYS_C_SRCS})
+  SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}_c PROPERTY LABELS ${KWSYS_LABELS_LIB})
+
+  # Apply user-defined target properties to the library.
+  IF(KWSYS_PROPERTIES_C)
+    SET_TARGET_PROPERTIES(${KWSYS_NAMESPACE}_c PROPERTIES
+      ${KWSYS_PROPERTIES_C}
+      )
+  ENDIF()
+
+  # Create an install target for the library.
+  IF(KWSYS_INSTALL_LIBRARY_RULE)
+    INSTALL(TARGETS ${KWSYS_NAMESPACE}_c ${KWSYS_INSTALL_LIBRARY_RULE})
+  ENDIF()
+ENDIF()
+
+# For building kwsys itself, we use a macro defined on the command
+# line to configure the namespace in the C and C++ source files.
+ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}")
+
+# Disable deprecation warnings for standard C functions.
+IF(MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Intel"))
+  ADD_DEFINITIONS(
+    -D_CRT_NONSTDC_NO_DEPRECATE
+    -D_CRT_SECURE_NO_DEPRECATE
+    -D_CRT_SECURE_NO_WARNINGS
+    -D_SCL_SECURE_NO_DEPRECATE
+    )
+ENDIF()
+
+IF(WIN32)
+  # Help enforce the use of wide Windows apis.
+  ADD_DEFINITIONS(-DUNICODE -D_UNICODE)
+ENDIF()
+
+IF(KWSYS_USE_String)
+  # Activate code in "String.c".  See the comment in the source.
+  SET_SOURCE_FILES_PROPERTIES(String.c PROPERTIES
+    COMPILE_FLAGS "-DKWSYS_STRING_C")
+ENDIF()
+
+IF(KWSYS_USE_Encoding)
+  # Set default 8 bit encoding in "EndcodingC.c".
+  SET_PROPERTY(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+    KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Setup testing if not being built as part of another project.
+IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
+  IF(BUILD_TESTING)
+    # Compute the location of executables.
+    SET(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+    IF(EXECUTABLE_OUTPUT_PATH)
+      SET(EXEC_DIR "${EXECUTABLE_OUTPUT_PATH}")
+    ENDIF()
+
+    # C tests
+    SET(KWSYS_C_TESTS
+      testEncode
+      testTerminal
+      )
+    IF(KWSYS_STANDALONE)
+      SET(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail)
+    ENDIF()
+    CREATE_TEST_SOURCELIST(
+      KWSYS_C_TEST_SRCS ${KWSYS_NAMESPACE}TestsC.c
+      ${KWSYS_C_TESTS}
+      )
+    ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS})
+    SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE})
+    TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsC ${KWSYS_NAMESPACE}_c)
+    FOREACH(test ${KWSYS_C_TESTS})
+      ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}})
+      SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+    ENDFOREACH()
+
+    # C++ tests
+    IF(NOT WATCOM)
+      SET(KWSYS_CXX_TESTS
+        testHashSTL
+        )
+    ENDIF()
+    SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+      testIOS
+      testSystemTools
+      testCommandLineArguments
+      testCommandLineArguments1
+      )
+    IF(KWSYS_STL_HAS_WSTRING)
+      SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+        testEncoding
+        )
+    ENDIF()
+    IF(KWSYS_USE_FStream)
+      SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+        testFStream
+        )
+    ENDIF()
+    IF(KWSYS_USE_ConsoleBuf)
+      ADD_EXECUTABLE(testConsoleBufChild testConsoleBufChild.cxx)
+      SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_INCLUDE_WHAT_YOU_USE "")
+      SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
+      SET_PROPERTY(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE})
+      TARGET_LINK_LIBRARIES(testConsoleBufChild ${KWSYS_NAMESPACE})
+      SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+        testConsoleBuf
+        )
+      IF("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" AND
+         CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506")
+        set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8)
+      ENDIF()
+      SET_PROPERTY(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+        KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
+    ENDIF()
+    IF(KWSYS_USE_SystemInformation)
+      SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation)
+    ENDIF()
+    IF(KWSYS_USE_DynamicLoader)
+      SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader)
+      # If kwsys contains the DynamicLoader, need extra library
+      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_NAMESPACE})
+    ENDIF()
+    CREATE_TEST_SOURCELIST(
+      KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
+      ${KWSYS_CXX_TESTS}
+      )
+    ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS})
+    SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "")
+    SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
+    SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE})
+    TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_NAMESPACE})
+
+    SET(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+    SET(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+    CONFIGURE_FILE(
+      ${PROJECT_SOURCE_DIR}/testSystemTools.h.in
+      ${PROJECT_BINARY_DIR}/testSystemTools.h)
+    INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR})
+
+    IF(CTEST_TEST_KWSYS)
+      CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in"
+        "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
+      SET_DIRECTORY_PROPERTIES(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
+    ENDIF()
+
+    SET(KWSYS_TEST_ARGS_testCommandLineArguments
+      --another-bool-variable
+      --long3=opt
+      --set-bool-arg1
+      -SSS ken brad bill andy
+      --some-bool-variable=true
+      --some-double-variable12.5
+      --some-int-variable 14
+      "--some-string-variable=test string with space"
+      --some-multi-argument 5 1 8 3 7 1 3 9 7 1
+      -N 12.5 -SS=andy -N 1.31 -N 22
+      -SS=bill -BBtrue -SS=brad
+      -BBtrue
+      -BBfalse
+      -SS=ken
+      -A
+      -C=test
+      --long2 hello
+      )
+    SET(KWSYS_TEST_ARGS_testCommandLineArguments1
+      --ignored
+      -n 24
+      --second-ignored
+      "-m=test value"
+      third-ignored
+      -p
+      some junk at the end
+      )
+    FOREACH(test ${KWSYS_CXX_TESTS})
+      ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}})
+      SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+    ENDFOREACH()
+
+    # Process tests.
+    ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestProcess testProcess.c)
+    SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE})
+    TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestProcess ${KWSYS_NAMESPACE}_c)
+    IF(NOT CYGWIN)
+      SET(KWSYS_TEST_PROCESS_7 7)
+    ENDIF()
+    FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10)
+      ADD_TEST(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n})
+      SET_PROPERTY(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST})
+      SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120)
+    ENDFOREACH()
+
+    # Some Apple compilers produce bad optimizations in this source.
+    IF(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$")
+      SET_SOURCE_FILES_PROPERTIES(testProcess.c PROPERTIES COMPILE_FLAGS -O0)
+    ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "XL")
+      # Tell IBM XL not to warn about our test infinite loop
+      SET_PROPERTY(SOURCE testProcess.c PROPERTY COMPILE_FLAGS -qsuppress=1500-010)
+    ENDIF()
+
+    # Test SharedForward
+    CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/testSharedForward.c.in
+                   ${PROJECT_BINARY_DIR}/testSharedForward.c @ONLY IMMEDIATE)
+    ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestSharedForward
+                   ${PROJECT_BINARY_DIR}/testSharedForward.c)
+    SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestSharedForward PROPERTY LABELS ${KWSYS_LABELS_EXE})
+    ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestSharedForward ${KWSYS_NAMESPACE}_c)
+    ADD_TEST(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1)
+    SET_PROPERTY(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST})
+
+    # Configure some test properties.
+    IF(KWSYS_STANDALONE)
+      # We expect test to fail
+      SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES WILL_FAIL ON)
+      GET_TEST_PROPERTY(kwsys.testFail WILL_FAIL wfv)
+      SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value")
+      MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}")
+    ENDIF()
+
+    # Set up ctest custom configuration file.
+    CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in
+                   ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY)
+
+    # Suppress known consistent failures on buggy systems.
+    IF(KWSYS_TEST_BOGUS_FAILURES)
+      SET_TESTS_PROPERTIES(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON)
+    ENDIF()
+
+  ENDIF()
+ENDIF()
diff --git a/thirdparty/KWSys/adios2sys/CONTRIBUTING.rst b/thirdparty/KWSys/adios2sys/CONTRIBUTING.rst
new file mode 100644
index 0000000000000000000000000000000000000000..d71832a1bc5b2eae1fa671b01fc85834cd3901de
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/CONTRIBUTING.rst
@@ -0,0 +1,47 @@
+Contributing to KWSys
+*********************
+
+Patches
+=======
+
+KWSys is kept in its own Git repository and shared by several projects
+via copies in their source trees.  Changes to KWSys should not be made
+directly in a host project, except perhaps in maintenance branches.
+
+KWSys uses `Kitware's GitLab Instance`_ to manage development and code review.
+To contribute patches:
+
+#. Fork the upstream `KWSys Repository`_ into a personal account.
+#. Base all new work on the upstream ``master`` branch.
+#. Run ``./SetupForDevelopment.sh`` in new local work trees.
+#. Create commits making incremental, distinct, logically complete changes.
+#. Push a topic branch to a personal repository fork on GitLab.
+#. Create a GitLab Merge Request targeting the upstream ``master`` branch.
+
+Once changes are reviewed, tested, and integrated to KWSys upstream then
+copies of KWSys within dependent projects can be updated to get the changes.
+
+.. _`Kitware's GitLab Instance`: https://gitlab.kitware.com
+.. _`KWSys Repository`: https://gitlab.kitware.com/utils/kwsys
+
+Code Style
+==========
+
+We use `clang-format`_ to define our style for C++ code in the KWSys source
+tree.  See the `.clang-format`_ configuration file for our style settings.
+Use ``clang-format`` version 3.8 or higher to format source files.
+See also the `clang-format.bash`_ script.
+
+.. _`clang-format`: http://clang.llvm.org/docs/ClangFormat.html
+.. _`.clang-format`: .clang-format
+.. _`clang-format.bash`: clang-format.bash
+
+License
+=======
+
+We do not require any formal copyright assignment or contributor license
+agreement.  Any contributions intentionally sent upstream are presumed
+to be offered under terms of the OSI-approved BSD 3-clause License.
+See `Copyright.txt`_ for details.
+
+.. _`Copyright.txt`: Copyright.txt
diff --git a/thirdparty/KWSys/adios2sys/CTestConfig.cmake b/thirdparty/KWSys/adios2sys/CTestConfig.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..1339ffc2ddc03af269ea0ba373fcf4e532dec254
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/CTestConfig.cmake
@@ -0,0 +1,9 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
+
+set(CTEST_PROJECT_NAME "KWSys")
+set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "open.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=KWSys")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/thirdparty/KWSys/adios2sys/CTestCustom.cmake.in b/thirdparty/KWSys/adios2sys/CTestCustom.cmake.in
new file mode 100644
index 0000000000000000000000000000000000000000..760221b124439a5ed7835d2ce2073deb0ab2a583
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/CTestCustom.cmake.in
@@ -0,0 +1,14 @@
+# kwsys.testProcess-10 involves sending SIGINT to a child process, which then
+# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess).
+# Naturally, this results in plenty of memory being "leaked" by this child
+# process - the memory check results are not meaningful in this case.
+#
+# kwsys.testProcess-9 also tests sending SIGINT to a child process.  However,
+# normal operation of that test involves the child process timing out, and the
+# host process kills (SIGKILL) it as a result.  Since it was SIGKILL'ed, the
+# resulting memory leaks are not logged by valgrind anyway.  Therefore, we
+# don't have to exclude it.
+
+list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE
+  kwsys.testProcess-10
+  )
diff --git a/thirdparty/KWSys/adios2sys/CommandLineArguments.cxx b/thirdparty/KWSys/adios2sys/CommandLineArguments.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..226263cc941b15867699e0840da83ddacda68c23
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/CommandLineArguments.cxx
@@ -0,0 +1,809 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(CommandLineArguments.hxx)
+
+#include KWSYS_HEADER(Configure.hxx)
+#include KWSYS_HEADER(String.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "CommandLineArguments.hxx.in"
+#include "Configure.hxx.in"
+#include "String.hxx.in"
+#endif
+
+#include <iostream>
+#include <map>
+#include <set>
+#include <sstream>
+#include <vector>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__)
+#pragma set woff 1375 /* base class destructor not virtual */
+#endif
+
+#if 0
+#define CommandLineArguments_DEBUG(x)                                         \
+  std::cout << __LINE__ << " CLA: " << x << std::endl
+#else
+#define CommandLineArguments_DEBUG(x)
+#endif
+
+namespace KWSYS_NAMESPACE {
+
+//----------------------------------------------------------------------------
+//============================================================================
+struct CommandLineArgumentsCallbackStructure
+{
+  const char* Argument;
+  int ArgumentType;
+  CommandLineArguments::CallbackType Callback;
+  void* CallData;
+  void* Variable;
+  int VariableType;
+  const char* Help;
+};
+
+class CommandLineArgumentsVectorOfStrings : public std::vector<kwsys::String>
+{
+};
+class CommandLineArgumentsSetOfStrings : public std::set<kwsys::String>
+{
+};
+class CommandLineArgumentsMapOfStrucs
+  : public std::map<kwsys::String, CommandLineArgumentsCallbackStructure>
+{
+};
+
+class CommandLineArgumentsInternal
+{
+public:
+  CommandLineArgumentsInternal()
+  {
+    this->UnknownArgumentCallback = 0;
+    this->ClientData = 0;
+    this->LastArgument = 0;
+  }
+
+  typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
+  typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
+  typedef kwsys::String String;
+  typedef CommandLineArgumentsSetOfStrings SetOfStrings;
+
+  VectorOfStrings Argv;
+  String Argv0;
+  CallbacksMap Callbacks;
+
+  CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
+  void* ClientData;
+
+  VectorOfStrings::size_type LastArgument;
+
+  VectorOfStrings UnusedArguments;
+};
+//============================================================================
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+CommandLineArguments::CommandLineArguments()
+{
+  this->Internals = new CommandLineArguments::Internal;
+  this->Help = "";
+  this->LineLength = 80;
+  this->StoreUnusedArgumentsFlag = false;
+}
+
+//----------------------------------------------------------------------------
+CommandLineArguments::~CommandLineArguments()
+{
+  delete this->Internals;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::Initialize(int argc, const char* const argv[])
+{
+  int cc;
+
+  this->Initialize();
+  this->Internals->Argv0 = argv[0];
+  for (cc = 1; cc < argc; cc++) {
+    this->ProcessArgument(argv[cc]);
+  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::Initialize(int argc, char* argv[])
+{
+  this->Initialize(argc, static_cast<const char* const*>(argv));
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::Initialize()
+{
+  this->Internals->Argv.clear();
+  this->Internals->LastArgument = 0;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::ProcessArgument(const char* arg)
+{
+  this->Internals->Argv.push_back(arg);
+}
+
+//----------------------------------------------------------------------------
+bool CommandLineArguments::GetMatchedArguments(
+  std::vector<std::string>* matches, const std::string& arg)
+{
+  matches->clear();
+  CommandLineArguments::Internal::CallbacksMap::iterator it;
+
+  // Does the argument match to any we know about?
+  for (it = this->Internals->Callbacks.begin();
+       it != this->Internals->Callbacks.end(); it++) {
+    const CommandLineArguments::Internal::String& parg = it->first;
+    CommandLineArgumentsCallbackStructure* cs = &it->second;
+    if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
+        cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) {
+      if (arg == parg) {
+        matches->push_back(parg);
+      }
+    } else if (arg.find(parg) == 0) {
+      matches->push_back(parg);
+    }
+  }
+  return !matches->empty();
+}
+
+//----------------------------------------------------------------------------
+int CommandLineArguments::Parse()
+{
+  std::vector<std::string>::size_type cc;
+  std::vector<std::string> matches;
+  if (this->StoreUnusedArgumentsFlag) {
+    this->Internals->UnusedArguments.clear();
+  }
+  for (cc = 0; cc < this->Internals->Argv.size(); cc++) {
+    const std::string& arg = this->Internals->Argv[cc];
+    CommandLineArguments_DEBUG("Process argument: " << arg);
+    this->Internals->LastArgument = cc;
+    if (this->GetMatchedArguments(&matches, arg)) {
+      // Ok, we found one or more arguments that match what user specified.
+      // Let's find the longest one.
+      CommandLineArguments::Internal::VectorOfStrings::size_type kk;
+      CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0;
+      CommandLineArguments::Internal::String::size_type maxlen = 0;
+      for (kk = 0; kk < matches.size(); kk++) {
+        if (matches[kk].size() > maxlen) {
+          maxlen = matches[kk].size();
+          maxidx = kk;
+        }
+      }
+      // So, the longest one is probably the right one. Now see if it has any
+      // additional value
+      CommandLineArgumentsCallbackStructure* cs =
+        &this->Internals->Callbacks[matches[maxidx]];
+      const std::string& sarg = matches[maxidx];
+      if (cs->Argument != sarg) {
+        abort();
+      }
+      switch (cs->ArgumentType) {
+        case NO_ARGUMENT:
+          // No value
+          if (!this->PopulateVariable(cs, 0)) {
+            return 0;
+          }
+          break;
+        case SPACE_ARGUMENT:
+          if (cc == this->Internals->Argv.size() - 1) {
+            this->Internals->LastArgument--;
+            return 0;
+          }
+          CommandLineArguments_DEBUG("This is a space argument: "
+                                     << arg << " value: "
+                                     << this->Internals->Argv[cc + 1]);
+          // Value is the next argument
+          if (!this->PopulateVariable(cs,
+                                      this->Internals->Argv[cc + 1].c_str())) {
+            return 0;
+          }
+          cc++;
+          break;
+        case EQUAL_ARGUMENT:
+          if (arg.size() == sarg.size() || arg.at(sarg.size()) != '=') {
+            this->Internals->LastArgument--;
+            return 0;
+          }
+          // Value is everythng followed the '=' sign
+          if (!this->PopulateVariable(cs, arg.c_str() + sarg.size() + 1)) {
+            return 0;
+          }
+          break;
+        case CONCAT_ARGUMENT:
+          // Value is whatever follows the argument
+          if (!this->PopulateVariable(cs, arg.c_str() + sarg.size())) {
+            return 0;
+          }
+          break;
+        case MULTI_ARGUMENT:
+          // Suck in all the rest of the arguments
+          CommandLineArguments_DEBUG("This is a multi argument: " << arg);
+          for (cc++; cc < this->Internals->Argv.size(); ++cc) {
+            const std::string& marg = this->Internals->Argv[cc];
+            CommandLineArguments_DEBUG(
+              " check multi argument value: " << marg);
+            if (this->GetMatchedArguments(&matches, marg)) {
+              CommandLineArguments_DEBUG("End of multi argument "
+                                         << arg << " with value: " << marg);
+              break;
+            }
+            CommandLineArguments_DEBUG(
+              " populate multi argument value: " << marg);
+            if (!this->PopulateVariable(cs, marg.c_str())) {
+              return 0;
+            }
+          }
+          if (cc != this->Internals->Argv.size()) {
+            CommandLineArguments_DEBUG("Again End of multi argument " << arg);
+            cc--;
+            continue;
+          }
+          break;
+        default:
+          std::cerr << "Got unknown argument type: \"" << cs->ArgumentType
+                    << "\"" << std::endl;
+          this->Internals->LastArgument--;
+          return 0;
+      }
+    } else {
+      // Handle unknown arguments
+      if (this->Internals->UnknownArgumentCallback) {
+        if (!this->Internals->UnknownArgumentCallback(
+              arg.c_str(), this->Internals->ClientData)) {
+          this->Internals->LastArgument--;
+          return 0;
+        }
+        return 1;
+      } else if (this->StoreUnusedArgumentsFlag) {
+        CommandLineArguments_DEBUG("Store unused argument " << arg);
+        this->Internals->UnusedArguments.push_back(arg);
+      } else {
+        std::cerr << "Got unknown argument: \"" << arg << "\"" << std::endl;
+        this->Internals->LastArgument--;
+        return 0;
+      }
+    }
+  }
+  return 1;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv)
+{
+  CommandLineArguments::Internal::VectorOfStrings::size_type size =
+    this->Internals->Argv.size() - this->Internals->LastArgument + 1;
+  CommandLineArguments::Internal::VectorOfStrings::size_type cc;
+
+  // Copy Argv0 as the first argument
+  char** args = new char*[size];
+  args[0] = new char[this->Internals->Argv0.size() + 1];
+  strcpy(args[0], this->Internals->Argv0.c_str());
+  int cnt = 1;
+
+  // Copy everything after the LastArgument, since that was not parsed.
+  for (cc = this->Internals->LastArgument + 1;
+       cc < this->Internals->Argv.size(); cc++) {
+    args[cnt] = new char[this->Internals->Argv[cc].size() + 1];
+    strcpy(args[cnt], this->Internals->Argv[cc].c_str());
+    cnt++;
+  }
+  *argc = cnt;
+  *argv = args;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::GetUnusedArguments(int* argc, char*** argv)
+{
+  CommandLineArguments::Internal::VectorOfStrings::size_type size =
+    this->Internals->UnusedArguments.size() + 1;
+  CommandLineArguments::Internal::VectorOfStrings::size_type cc;
+
+  // Copy Argv0 as the first argument
+  char** args = new char*[size];
+  args[0] = new char[this->Internals->Argv0.size() + 1];
+  strcpy(args[0], this->Internals->Argv0.c_str());
+  int cnt = 1;
+
+  // Copy everything after the LastArgument, since that was not parsed.
+  for (cc = 0; cc < this->Internals->UnusedArguments.size(); cc++) {
+    kwsys::String& str = this->Internals->UnusedArguments[cc];
+    args[cnt] = new char[str.size() + 1];
+    strcpy(args[cnt], str.c_str());
+    cnt++;
+  }
+  *argc = cnt;
+  *argv = args;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv)
+{
+  int cc;
+  for (cc = 0; cc < argc; ++cc) {
+    delete[](*argv)[cc];
+  }
+  delete[] * argv;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::AddCallback(const char* argument,
+                                       ArgumentTypeEnum type,
+                                       CallbackType callback, void* call_data,
+                                       const char* help)
+{
+  CommandLineArgumentsCallbackStructure s;
+  s.Argument = argument;
+  s.ArgumentType = type;
+  s.Callback = callback;
+  s.CallData = call_data;
+  s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
+  s.Variable = 0;
+  s.Help = help;
+
+  this->Internals->Callbacks[argument] = s;
+  this->GenerateHelp();
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::AddArgument(const char* argument,
+                                       ArgumentTypeEnum type,
+                                       VariableTypeEnum vtype, void* variable,
+                                       const char* help)
+{
+  CommandLineArgumentsCallbackStructure s;
+  s.Argument = argument;
+  s.ArgumentType = type;
+  s.Callback = 0;
+  s.CallData = 0;
+  s.VariableType = vtype;
+  s.Variable = variable;
+  s.Help = help;
+
+  this->Internals->Callbacks[argument] = s;
+  this->GenerateHelp();
+}
+
+//----------------------------------------------------------------------------
+#define CommandLineArgumentsAddArgumentMacro(type, ctype)                     \
+  void CommandLineArguments::AddArgument(const char* argument,                \
+                                         ArgumentTypeEnum type,               \
+                                         ctype* variable, const char* help)   \
+  {                                                                           \
+    this->AddArgument(argument, type, CommandLineArguments::type##_TYPE,      \
+                      variable, help);                                        \
+  }
+
+CommandLineArgumentsAddArgumentMacro(BOOL, bool)
+  CommandLineArgumentsAddArgumentMacro(INT, int)
+    CommandLineArgumentsAddArgumentMacro(DOUBLE, double)
+      CommandLineArgumentsAddArgumentMacro(STRING, char*)
+        CommandLineArgumentsAddArgumentMacro(STL_STRING, std::string)
+
+          CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL, std::vector<bool>)
+            CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector<int>)
+              CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE,
+                                                   std::vector<double>)
+                CommandLineArgumentsAddArgumentMacro(VECTOR_STRING,
+                                                     std::vector<char*>)
+                  CommandLineArgumentsAddArgumentMacro(
+                    VECTOR_STL_STRING, std::vector<std::string>)
+
+//----------------------------------------------------------------------------
+#define CommandLineArgumentsAddBooleanArgumentMacro(type, ctype)              \
+  void CommandLineArguments::AddBooleanArgument(                              \
+    const char* argument, ctype* variable, const char* help)                  \
+  {                                                                           \
+    this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,            \
+                      CommandLineArguments::type##_TYPE, variable, help);     \
+  }
+
+                    CommandLineArgumentsAddBooleanArgumentMacro(BOOL, bool)
+                      CommandLineArgumentsAddBooleanArgumentMacro(INT, int)
+                        CommandLineArgumentsAddBooleanArgumentMacro(DOUBLE,
+                                                                    double)
+                          CommandLineArgumentsAddBooleanArgumentMacro(STRING,
+                                                                      char*)
+                            CommandLineArgumentsAddBooleanArgumentMacro(
+                              STL_STRING, std::string)
+
+  //----------------------------------------------------------------------------
+  void CommandLineArguments::SetClientData(void* client_data)
+{
+  this->Internals->ClientData = client_data;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::SetUnknownArgumentCallback(
+  CommandLineArguments::ErrorCallbackType callback)
+{
+  this->Internals->UnknownArgumentCallback = callback;
+}
+
+//----------------------------------------------------------------------------
+const char* CommandLineArguments::GetHelp(const char* arg)
+{
+  CommandLineArguments::Internal::CallbacksMap::iterator it =
+    this->Internals->Callbacks.find(arg);
+  if (it == this->Internals->Callbacks.end()) {
+    return 0;
+  }
+
+  // Since several arguments may point to the same argument, find the one this
+  // one point to if this one is pointing to another argument.
+  CommandLineArgumentsCallbackStructure* cs = &(it->second);
+  for (;;) {
+    CommandLineArguments::Internal::CallbacksMap::iterator hit =
+      this->Internals->Callbacks.find(cs->Help);
+    if (hit == this->Internals->Callbacks.end()) {
+      break;
+    }
+    cs = &(hit->second);
+  }
+  return cs->Help;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::SetLineLength(unsigned int ll)
+{
+  if (ll < 9 || ll > 1000) {
+    return;
+  }
+  this->LineLength = ll;
+  this->GenerateHelp();
+}
+
+//----------------------------------------------------------------------------
+const char* CommandLineArguments::GetArgv0()
+{
+  return this->Internals->Argv0.c_str();
+}
+
+//----------------------------------------------------------------------------
+unsigned int CommandLineArguments::GetLastArgument()
+{
+  return static_cast<unsigned int>(this->Internals->LastArgument + 1);
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::GenerateHelp()
+{
+  std::ostringstream str;
+
+  // Collapse all arguments into the map of vectors of all arguments that do
+  // the same thing.
+  CommandLineArguments::Internal::CallbacksMap::iterator it;
+  typedef std::map<CommandLineArguments::Internal::String,
+                   CommandLineArguments::Internal::SetOfStrings>
+    MapArgs;
+  MapArgs mp;
+  MapArgs::iterator mpit, smpit;
+  for (it = this->Internals->Callbacks.begin();
+       it != this->Internals->Callbacks.end(); it++) {
+    CommandLineArgumentsCallbackStructure* cs = &(it->second);
+    mpit = mp.find(cs->Help);
+    if (mpit != mp.end()) {
+      mpit->second.insert(it->first);
+      mp[it->first].insert(it->first);
+    } else {
+      mp[it->first].insert(it->first);
+    }
+  }
+  for (it = this->Internals->Callbacks.begin();
+       it != this->Internals->Callbacks.end(); it++) {
+    CommandLineArgumentsCallbackStructure* cs = &(it->second);
+    mpit = mp.find(cs->Help);
+    if (mpit != mp.end()) {
+      mpit->second.insert(it->first);
+      smpit = mp.find(it->first);
+      CommandLineArguments::Internal::SetOfStrings::iterator sit;
+      for (sit = smpit->second.begin(); sit != smpit->second.end(); sit++) {
+        mpit->second.insert(*sit);
+      }
+      mp.erase(smpit);
+    } else {
+      mp[it->first].insert(it->first);
+    }
+  }
+
+  // Find the length of the longest string
+  CommandLineArguments::Internal::String::size_type maxlen = 0;
+  for (mpit = mp.begin(); mpit != mp.end(); mpit++) {
+    CommandLineArguments::Internal::SetOfStrings::iterator sit;
+    for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) {
+      CommandLineArguments::Internal::String::size_type clen = sit->size();
+      switch (this->Internals->Callbacks[*sit].ArgumentType) {
+        case CommandLineArguments::NO_ARGUMENT:
+          clen += 0;
+          break;
+        case CommandLineArguments::CONCAT_ARGUMENT:
+          clen += 3;
+          break;
+        case CommandLineArguments::SPACE_ARGUMENT:
+          clen += 4;
+          break;
+        case CommandLineArguments::EQUAL_ARGUMENT:
+          clen += 4;
+          break;
+      }
+      if (clen > maxlen) {
+        maxlen = clen;
+      }
+    }
+  }
+
+  // Create format for that string
+  char format[80];
+  sprintf(format, "  %%-%us  ", static_cast<unsigned int>(maxlen));
+
+  maxlen += 4; // For the space before and after the option
+
+  // Print help for each option
+  for (mpit = mp.begin(); mpit != mp.end(); mpit++) {
+    CommandLineArguments::Internal::SetOfStrings::iterator sit;
+    for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) {
+      str << std::endl;
+      char argument[100];
+      sprintf(argument, "%s", sit->c_str());
+      switch (this->Internals->Callbacks[*sit].ArgumentType) {
+        case CommandLineArguments::NO_ARGUMENT:
+          break;
+        case CommandLineArguments::CONCAT_ARGUMENT:
+          strcat(argument, "opt");
+          break;
+        case CommandLineArguments::SPACE_ARGUMENT:
+          strcat(argument, " opt");
+          break;
+        case CommandLineArguments::EQUAL_ARGUMENT:
+          strcat(argument, "=opt");
+          break;
+        case CommandLineArguments::MULTI_ARGUMENT:
+          strcat(argument, " opt opt ...");
+          break;
+      }
+      char buffer[80];
+      sprintf(buffer, format, argument);
+      str << buffer;
+    }
+    const char* ptr = this->Internals->Callbacks[mpit->first].Help;
+    size_t len = strlen(ptr);
+    int cnt = 0;
+    while (len > 0) {
+      // If argument with help is longer than line length, split it on previous
+      // space (or tab) and continue on the next line
+      CommandLineArguments::Internal::String::size_type cc;
+      for (cc = 0; ptr[cc]; cc++) {
+        if (*ptr == ' ' || *ptr == '\t') {
+          ptr++;
+          len--;
+        }
+      }
+      if (cnt > 0) {
+        for (cc = 0; cc < maxlen; cc++) {
+          str << " ";
+        }
+      }
+      CommandLineArguments::Internal::String::size_type skip = len;
+      if (skip > this->LineLength - maxlen) {
+        skip = this->LineLength - maxlen;
+        for (cc = skip - 1; cc > 0; cc--) {
+          if (ptr[cc] == ' ' || ptr[cc] == '\t') {
+            break;
+          }
+        }
+        if (cc != 0) {
+          skip = cc;
+        }
+      }
+      str.write(ptr, static_cast<std::streamsize>(skip));
+      str << std::endl;
+      ptr += skip;
+      len -= skip;
+      cnt++;
+    }
+  }
+  /*
+  // This can help debugging help string
+  str << endl;
+  unsigned int cc;
+  for ( cc = 0; cc < this->LineLength; cc ++ )
+    {
+    str << cc % 10;
+    }
+  str << endl;
+  */
+  this->Help = str.str();
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(bool* variable,
+                                            const std::string& value)
+{
+  if (value == "1" || value == "ON" || value == "on" || value == "On" ||
+      value == "TRUE" || value == "true" || value == "True" ||
+      value == "yes" || value == "Yes" || value == "YES") {
+    *variable = true;
+  } else {
+    *variable = false;
+  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(int* variable,
+                                            const std::string& value)
+{
+  char* res = 0;
+  *variable = static_cast<int>(strtol(value.c_str(), &res, 10));
+  // if ( res && *res )
+  //  {
+  //  Can handle non-int
+  //  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(double* variable,
+                                            const std::string& value)
+{
+  char* res = 0;
+  *variable = strtod(value.c_str(), &res);
+  // if ( res && *res )
+  //  {
+  //  Can handle non-double
+  //  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(char** variable,
+                                            const std::string& value)
+{
+  if (*variable) {
+    delete[] * variable;
+    *variable = 0;
+  }
+  *variable = new char[value.size() + 1];
+  strcpy(*variable, value.c_str());
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(std::string* variable,
+                                            const std::string& value)
+{
+  *variable = value;
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(std::vector<bool>* variable,
+                                            const std::string& value)
+{
+  bool val = false;
+  if (value == "1" || value == "ON" || value == "on" || value == "On" ||
+      value == "TRUE" || value == "true" || value == "True" ||
+      value == "yes" || value == "Yes" || value == "YES") {
+    val = true;
+  }
+  variable->push_back(val);
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(std::vector<int>* variable,
+                                            const std::string& value)
+{
+  char* res = 0;
+  variable->push_back(static_cast<int>(strtol(value.c_str(), &res, 10)));
+  // if ( res && *res )
+  //  {
+  //  Can handle non-int
+  //  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(std::vector<double>* variable,
+                                            const std::string& value)
+{
+  char* res = 0;
+  variable->push_back(strtod(value.c_str(), &res));
+  // if ( res && *res )
+  //  {
+  //  Can handle non-int
+  //  }
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(std::vector<char*>* variable,
+                                            const std::string& value)
+{
+  char* var = new char[value.size() + 1];
+  strcpy(var, value.c_str());
+  variable->push_back(var);
+}
+
+//----------------------------------------------------------------------------
+void CommandLineArguments::PopulateVariable(std::vector<std::string>* variable,
+                                            const std::string& value)
+{
+  variable->push_back(value);
+}
+
+//----------------------------------------------------------------------------
+bool CommandLineArguments::PopulateVariable(
+  CommandLineArgumentsCallbackStructure* cs, const char* value)
+{
+  // Call the callback
+  if (cs->Callback) {
+    if (!cs->Callback(cs->Argument, value, cs->CallData)) {
+      this->Internals->LastArgument--;
+      return 0;
+    }
+  }
+  CommandLineArguments_DEBUG("Set argument: " << cs->Argument << " to "
+                                              << value);
+  if (cs->Variable) {
+    std::string var = "1";
+    if (value) {
+      var = value;
+    }
+    switch (cs->VariableType) {
+      case CommandLineArguments::INT_TYPE:
+        this->PopulateVariable(static_cast<int*>(cs->Variable), var);
+        break;
+      case CommandLineArguments::DOUBLE_TYPE:
+        this->PopulateVariable(static_cast<double*>(cs->Variable), var);
+        break;
+      case CommandLineArguments::STRING_TYPE:
+        this->PopulateVariable(static_cast<char**>(cs->Variable), var);
+        break;
+      case CommandLineArguments::STL_STRING_TYPE:
+        this->PopulateVariable(static_cast<std::string*>(cs->Variable), var);
+        break;
+      case CommandLineArguments::BOOL_TYPE:
+        this->PopulateVariable(static_cast<bool*>(cs->Variable), var);
+        break;
+      case CommandLineArguments::VECTOR_BOOL_TYPE:
+        this->PopulateVariable(static_cast<std::vector<bool>*>(cs->Variable),
+                               var);
+        break;
+      case CommandLineArguments::VECTOR_INT_TYPE:
+        this->PopulateVariable(static_cast<std::vector<int>*>(cs->Variable),
+                               var);
+        break;
+      case CommandLineArguments::VECTOR_DOUBLE_TYPE:
+        this->PopulateVariable(static_cast<std::vector<double>*>(cs->Variable),
+                               var);
+        break;
+      case CommandLineArguments::VECTOR_STRING_TYPE:
+        this->PopulateVariable(static_cast<std::vector<char*>*>(cs->Variable),
+                               var);
+        break;
+      case CommandLineArguments::VECTOR_STL_STRING_TYPE:
+        this->PopulateVariable(
+          static_cast<std::vector<std::string>*>(cs->Variable), var);
+        break;
+      default:
+        std::cerr << "Got unknown variable type: \"" << cs->VariableType
+                  << "\"" << std::endl;
+        this->Internals->LastArgument--;
+        return 0;
+    }
+  }
+  return 1;
+}
+
+} // namespace KWSYS_NAMESPACE
diff --git a/thirdparty/KWSys/adios2sys/CommandLineArguments.hxx.in b/thirdparty/KWSys/adios2sys/CommandLineArguments.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..31115e51fb73e6a44ed1920bb58778f05c9f27b9
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/CommandLineArguments.hxx.in
@@ -0,0 +1,267 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_CommandLineArguments_hxx
+#define @KWSYS_NAMESPACE@_CommandLineArguments_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+#include <vector>
+
+namespace @KWSYS_NAMESPACE@ {
+
+class CommandLineArgumentsInternal;
+struct CommandLineArgumentsCallbackStructure;
+
+/** \class CommandLineArguments
+ * \brief Command line arguments processing code.
+ *
+ * Find specified arguments with optional options and execute specified methods
+ * or set given variables.
+ *
+ * The two interfaces it knows are callback based and variable based. For
+ * callback based, you have to register callback for particular argument using
+ * AddCallback method. When that argument is passed, the callback will be
+ * called with argument, value, and call data. For boolean (NO_ARGUMENT)
+ * arguments, the value is "1". If the callback returns 0 the argument parsing
+ * will stop with an error.
+ *
+ * For the variable interface you associate variable with each argument. When
+ * the argument is specified, the variable is set to the specified value casted
+ * to the appropriate type. For boolean (NO_ARGUMENT), the value is "1".
+ *
+ * Both interfaces can be used at the same time.
+ *
+ * Possible argument types are:
+ *   NO_ARGUMENT     - The argument takes no value             : --A
+ *   CONCAT_ARGUMENT - The argument takes value after no space : --Aval
+ *   SPACE_ARGUMENT  - The argument takes value after space    : --A val
+ *   EQUAL_ARGUMENT  - The argument takes value after equal    : --A=val
+ *   MULTI_ARGUMENT  - The argument takes values after space   : --A val1 val2
+ * val3 ...
+ *
+ * Example use:
+ *
+ * kwsys::CommandLineArguments arg;
+ * arg.Initialize(argc, argv);
+ * typedef kwsys::CommandLineArguments argT;
+ * arg.AddArgument("--something", argT::EQUAL_ARGUMENT, &some_variable,
+ *                 "This is help string for --something");
+ * if ( !arg.Parse() )
+ *   {
+ *   std::cerr << "Problem parsing arguments" << std::endl;
+ *   res = 1;
+ *   }
+ *
+ */
+
+class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments
+{
+public:
+  CommandLineArguments();
+  ~CommandLineArguments();
+
+  /**
+   * Various argument types.
+   */
+  enum ArgumentTypeEnum
+  {
+    NO_ARGUMENT,
+    CONCAT_ARGUMENT,
+    SPACE_ARGUMENT,
+    EQUAL_ARGUMENT,
+    MULTI_ARGUMENT
+  };
+
+  /**
+   * Various variable types. When using the variable interface, this specifies
+   * what type the variable is.
+   */
+  enum VariableTypeEnum
+  {
+    NO_VARIABLE_TYPE = 0,   // The variable is not specified
+    INT_TYPE,               // The variable is integer (int)
+    BOOL_TYPE,              // The variable is boolean (bool)
+    DOUBLE_TYPE,            // The variable is float (double)
+    STRING_TYPE,            // The variable is string (char*)
+    STL_STRING_TYPE,        // The variable is string (char*)
+    VECTOR_INT_TYPE,        // The variable is integer (int)
+    VECTOR_BOOL_TYPE,       // The variable is boolean (bool)
+    VECTOR_DOUBLE_TYPE,     // The variable is float (double)
+    VECTOR_STRING_TYPE,     // The variable is string (char*)
+    VECTOR_STL_STRING_TYPE, // The variable is string (char*)
+    LAST_VARIABLE_TYPE
+  };
+
+  /**
+   * Prototypes for callbacks for callback interface.
+   */
+  typedef int (*CallbackType)(const char* argument, const char* value,
+                              void* call_data);
+  typedef int (*ErrorCallbackType)(const char* argument, void* client_data);
+
+  /**
+   * Initialize internal data structures. This should be called before parsing.
+   */
+  void Initialize(int argc, const char* const argv[]);
+  void Initialize(int argc, char* argv[]);
+
+  /**
+   * Initialize internal data structure and pass arguments one by one. This is
+   * convenience method for use from scripting languages where argc and argv
+   * are not available.
+   */
+  void Initialize();
+  void ProcessArgument(const char* arg);
+
+  /**
+   * This method will parse arguments and call appropriate methods.
+   */
+  int Parse();
+
+  /**
+   * This method will add a callback for a specific argument. The arguments to
+   * it are argument, argument type, callback method, and call data. The
+   * argument help specifies the help string used with this option. The
+   * callback and call_data can be skipped.
+   */
+  void AddCallback(const char* argument, ArgumentTypeEnum type,
+                   CallbackType callback, void* call_data, const char* help);
+
+  /**
+   * Add handler for argument which is going to set the variable to the
+   * specified value. If the argument is specified, the option is casted to the
+   * appropriate type.
+   */
+  void AddArgument(const char* argument, ArgumentTypeEnum type, bool* variable,
+                   const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type, int* variable,
+                   const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   double* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   char** variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   std::string* variable, const char* help);
+
+  /**
+   * Add handler for argument which is going to set the variable to the
+   * specified value. If the argument is specified, the option is casted to the
+   * appropriate type. This will handle the multi argument values.
+   */
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   std::vector<bool>* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   std::vector<int>* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   std::vector<double>* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   std::vector<char*>* variable, const char* help);
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   std::vector<std::string>* variable, const char* help);
+
+  /**
+   * Add handler for boolean argument. The argument does not take any option
+   * and if it is specified, the value of the variable is true/1, otherwise it
+   * is false/0.
+   */
+  void AddBooleanArgument(const char* argument, bool* variable,
+                          const char* help);
+  void AddBooleanArgument(const char* argument, int* variable,
+                          const char* help);
+  void AddBooleanArgument(const char* argument, double* variable,
+                          const char* help);
+  void AddBooleanArgument(const char* argument, char** variable,
+                          const char* help);
+  void AddBooleanArgument(const char* argument, std::string* variable,
+                          const char* help);
+
+  /**
+   * Set the callbacks for error handling.
+   */
+  void SetClientData(void* client_data);
+  void SetUnknownArgumentCallback(ErrorCallbackType callback);
+
+  /**
+   * Get remaining arguments. It allocates space for argv, so you have to call
+   * delete[] on it.
+   */
+  void GetRemainingArguments(int* argc, char*** argv);
+  void DeleteRemainingArguments(int argc, char*** argv);
+
+  /**
+   * If StoreUnusedArguments is set to true, then all unknown arguments will be
+   * stored and the user can access the modified argc, argv without known
+   * arguments.
+   */
+  void StoreUnusedArguments(bool val) { this->StoreUnusedArgumentsFlag = val; }
+  void GetUnusedArguments(int* argc, char*** argv);
+
+  /**
+   * Return string containing help. If the argument is specified, only return
+   * help for that argument.
+   */
+  const char* GetHelp() { return this->Help.c_str(); }
+  const char* GetHelp(const char* arg);
+
+  /**
+   * Get / Set the help line length. This length is used when generating the
+   * help page. Default length is 80.
+   */
+  void SetLineLength(unsigned int);
+  unsigned int GetLineLength();
+
+  /**
+   * Get the executable name (argv0). This is only available when using
+   * Initialize with argc/argv.
+   */
+  const char* GetArgv0();
+
+  /**
+   * Get index of the last argument parsed. This is the last argument that was
+   * parsed ok in the original argc/argv list.
+   */
+  unsigned int GetLastArgument();
+
+protected:
+  void GenerateHelp();
+
+  //! This is internal method that registers variable with argument
+  void AddArgument(const char* argument, ArgumentTypeEnum type,
+                   VariableTypeEnum vtype, void* variable, const char* help);
+
+  bool GetMatchedArguments(std::vector<std::string>* matches,
+                           const std::string& arg);
+
+  //! Populate individual variables
+  bool PopulateVariable(CommandLineArgumentsCallbackStructure* cs,
+                        const char* value);
+
+  //! Populate individual variables of type ...
+  void PopulateVariable(bool* variable, const std::string& value);
+  void PopulateVariable(int* variable, const std::string& value);
+  void PopulateVariable(double* variable, const std::string& value);
+  void PopulateVariable(char** variable, const std::string& value);
+  void PopulateVariable(std::string* variable, const std::string& value);
+  void PopulateVariable(std::vector<bool>* variable, const std::string& value);
+  void PopulateVariable(std::vector<int>* variable, const std::string& value);
+  void PopulateVariable(std::vector<double>* variable,
+                        const std::string& value);
+  void PopulateVariable(std::vector<char*>* variable,
+                        const std::string& value);
+  void PopulateVariable(std::vector<std::string>* variable,
+                        const std::string& value);
+
+  typedef CommandLineArgumentsInternal Internal;
+  Internal* Internals;
+  std::string Help;
+
+  unsigned int LineLength;
+
+  bool StoreUnusedArgumentsFlag;
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Configure.h.in b/thirdparty/KWSys/adios2sys/Configure.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..0afcae781d6ae46d6e27b3864948e6915119e542
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Configure.h.in
@@ -0,0 +1,127 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Configure_h
+#define @KWSYS_NAMESPACE@_Configure_h
+
+/* If we are building a kwsys .c or .cxx file, let it use the kwsys
+   namespace.  When not building a kwsys source file these macros are
+   temporarily defined inside the headers that use them.  */
+#if defined(KWSYS_NAMESPACE)
+#define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+
+/* Disable some warnings inside kwsys source files.  */
+#if defined(KWSYS_NAMESPACE)
+#if defined(__BORLANDC__)
+#pragma warn - 8027 /* function not inlined.  */
+#endif
+#if defined(__INTEL_COMPILER)
+#pragma warning(disable : 1572) /* floating-point equality test */
+#endif
+#if defined(__sgi) && !defined(__GNUC__)
+#pragma set woff 3970 /* pointer to int conversion */
+#pragma set woff 3968 /* 64 bit conversion */
+#endif
+#endif
+
+/* Whether kwsys namespace is "kwsys".  */
+#define @KWSYS_NAMESPACE@_NAME_IS_KWSYS @KWSYS_NAME_IS_KWSYS@
+
+/* Whether Large File Support is requested.  */
+#define @KWSYS_NAMESPACE@_LFS_REQUESTED @KWSYS_LFS_REQUESTED@
+
+/* Whether Large File Support is available.  */
+#if @KWSYS_NAMESPACE@_LFS_REQUESTED
+#define @KWSYS_NAMESPACE@_LFS_AVAILABLE @KWSYS_LFS_AVAILABLE@
+#endif
+
+/* Setup Large File Support if requested.  */
+#if @KWSYS_NAMESPACE@_LFS_REQUESTED
+/* Since LFS is requested this header must be included before system
+   headers whether or not LFS is available. */
+#if 0 && (defined(_SYS_TYPES_H) || defined(_SYS_TYPES_INCLUDED))
+#error "@KWSYS_NAMESPACE@/Configure.h must be included before sys/types.h"
+#endif
+/* Enable the large file API if it is available.  */
+#if @KWSYS_NAMESPACE@_LFS_AVAILABLE &&                                        \
+  !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINES)
+#if !defined(_LARGEFILE_SOURCE) &&                                            \
+  !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE_SOURCE)
+#define _LARGEFILE_SOURCE
+#endif
+#if !defined(_LARGEFILE64_SOURCE) &&                                          \
+  !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE64_SOURCE)
+#define _LARGEFILE64_SOURCE
+#endif
+#if !defined(_LARGE_FILES) &&                                                 \
+  !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGE_FILES)
+#define _LARGE_FILES
+#endif
+#if !defined(_FILE_OFFSET_BITS) &&                                            \
+  !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_FILE_OFFSET_BITS)
+#define _FILE_OFFSET_BITS 64
+#endif
+#if 0 && (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
+#error "_FILE_OFFSET_BITS must be defined to at least 64"
+#endif
+#endif
+#endif
+
+/* Setup the export macro.  */
+#if @KWSYS_BUILD_SHARED@
+#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(@KWSYS_NAMESPACE@_EXPORTS)
+#define @KWSYS_NAMESPACE@_EXPORT __declspec(dllexport)
+#else
+#define @KWSYS_NAMESPACE@_EXPORT __declspec(dllimport)
+#endif
+#elif __GNUC__ >= 4
+#define @KWSYS_NAMESPACE@_EXPORT __attribute__((visibility("default")))
+#else
+#define @KWSYS_NAMESPACE@_EXPORT
+#endif
+#else
+#define @KWSYS_NAMESPACE@_EXPORT
+#endif
+
+/* Enable warnings that are off by default but are useful.  */
+#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_ENABLE)
+#if defined(_MSC_VER)
+#pragma warning(default : 4263) /* no override, call convention differs */
+#endif
+#endif
+
+/* Disable warnings that are on by default but occur in valid code.  */
+#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE)
+#if defined(_MSC_VER)
+#pragma warning(disable : 4097) /* typedef is synonym for class */
+#pragma warning(disable : 4127) /* conditional expression is constant */
+#pragma warning(disable : 4244) /* possible loss in conversion */
+#pragma warning(disable : 4251) /* missing DLL-interface */
+#pragma warning(disable : 4305) /* truncation from type1 to type2 */
+#pragma warning(disable : 4309) /* truncation of constant value */
+#pragma warning(disable : 4514) /* unreferenced inline function */
+#pragma warning(disable : 4706) /* assignment in conditional expression */
+#pragma warning(disable : 4710) /* function not inlined */
+#pragma warning(disable : 4786) /* identifier truncated in debug info */
+#endif
+#if defined(__BORLANDC__) && !defined(__cplusplus)
+/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an
+   unused parameter using "(param)" syntax (i.e. no cast to void).  */
+#pragma warn - 8019
+#endif
+#endif
+
+/* MSVC 6.0 in release mode will warn about code it produces with its
+   optimizer.  Disable the warnings specifically for this
+   configuration.  Real warnings will be revealed by a debug build or
+   by other compilers.  */
+#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE_BOGUS)
+#if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG)
+#pragma warning(disable : 4701) /* Variable may be used uninitialized.  */
+#pragma warning(disable : 4702) /* Unreachable code.  */
+#endif
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Configure.hxx.in b/thirdparty/KWSys/adios2sys/Configure.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..1c07a4ef78bd0dd2a06ab614814b93bfc4e5b9e7
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Configure.hxx.in
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Configure_hxx
+#define @KWSYS_NAMESPACE@_Configure_hxx
+
+/* Include C configuration.  */
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+/* Whether wstring is available.  */
+#define @KWSYS_NAMESPACE@_STL_HAS_WSTRING @KWSYS_STL_HAS_WSTRING@
+/* Whether <ext/stdio_filebuf.h> is available. */
+#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H                         \
+  @KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@
+
+/* If building a C++ file in kwsys itself, give the source file
+   access to the macros without a configured namespace.  */
+#if defined(KWSYS_NAMESPACE)
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsys @KWSYS_NAMESPACE@
+#endif
+#define KWSYS_NAME_IS_KWSYS @KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING
+#define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H                                     \
+  @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/ConsoleBuf.hxx.in b/thirdparty/KWSys/adios2sys/ConsoleBuf.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..32e680ca64010d6ccebf58d1975cf72d19092394
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/ConsoleBuf.hxx.in
@@ -0,0 +1,393 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_ConsoleBuf_hxx
+#define @KWSYS_NAMESPACE@_ConsoleBuf_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <@KWSYS_NAMESPACE@/Encoding.hxx>
+
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <streambuf>
+#include <string>
+
+#if defined(_WIN32)
+#include <windows.h>
+#if __cplusplus >= 201103L
+#include <system_error>
+#endif
+#endif
+
+namespace @KWSYS_NAMESPACE@ {
+#if defined(_WIN32)
+
+template <class CharT, class Traits = std::char_traits<CharT> >
+class BasicConsoleBuf : public std::basic_streambuf<CharT, Traits>
+{
+public:
+  typedef typename Traits::int_type int_type;
+  typedef typename Traits::char_type char_type;
+
+  class Manager
+  {
+  public:
+    Manager(std::basic_ios<CharT, Traits>& ios, const bool err = false)
+      : m_consolebuf(0)
+    {
+      m_ios = &ios;
+      try {
+        m_consolebuf = new BasicConsoleBuf<CharT, Traits>(err);
+        m_streambuf = m_ios->rdbuf(m_consolebuf);
+      } catch (const std::runtime_error& ex) {
+        std::cerr << "Failed to create ConsoleBuf!" << std::endl
+                  << ex.what() << std::endl;
+      };
+    }
+
+    BasicConsoleBuf<CharT, Traits>* GetConsoleBuf() { return m_consolebuf; }
+
+    void SetUTF8Pipes()
+    {
+      if (m_consolebuf) {
+        m_consolebuf->input_pipe_codepage = CP_UTF8;
+        m_consolebuf->output_pipe_codepage = CP_UTF8;
+        m_consolebuf->activateCodepageChange();
+      }
+    }
+
+    ~Manager()
+    {
+      if (m_consolebuf) {
+        delete m_consolebuf;
+        m_ios->rdbuf(m_streambuf);
+      }
+    }
+
+  private:
+    std::basic_ios<CharT, Traits>* m_ios;
+    std::basic_streambuf<CharT, Traits>* m_streambuf;
+    BasicConsoleBuf<CharT, Traits>* m_consolebuf;
+  };
+
+  BasicConsoleBuf(const bool err = false)
+    : flush_on_newline(true)
+    , input_pipe_codepage(0)
+    , output_pipe_codepage(0)
+    , input_file_codepage(CP_UTF8)
+    , output_file_codepage(CP_UTF8)
+    , m_consolesCodepage(0)
+  {
+    m_hInput = ::GetStdHandle(STD_INPUT_HANDLE);
+    checkHandle(true, "STD_INPUT_HANDLE");
+    if (!setActiveInputCodepage()) {
+      throw std::runtime_error("setActiveInputCodepage failed!");
+    }
+    m_hOutput = err ? ::GetStdHandle(STD_ERROR_HANDLE)
+                    : ::GetStdHandle(STD_OUTPUT_HANDLE);
+    checkHandle(false, err ? "STD_ERROR_HANDLE" : "STD_OUTPUT_HANDLE");
+    if (!setActiveOutputCodepage()) {
+      throw std::runtime_error("setActiveOutputCodepage failed!");
+    }
+    _setg();
+    _setp();
+  }
+
+  ~BasicConsoleBuf() throw() { sync(); }
+
+  bool activateCodepageChange()
+  {
+    return setActiveInputCodepage() && setActiveOutputCodepage();
+  }
+
+protected:
+  virtual int sync()
+  {
+    bool success = true;
+    if (m_hInput && m_isConsoleInput &&
+        ::FlushConsoleInputBuffer(m_hInput) == 0) {
+      success = false;
+    }
+    if (m_hOutput && !m_obuffer.empty()) {
+      const std::wstring wbuffer = getBuffer(m_obuffer);
+      if (m_isConsoleOutput) {
+        DWORD charsWritten;
+        success =
+          ::WriteConsoleW(m_hOutput, wbuffer.c_str(), (DWORD)wbuffer.size(),
+                          &charsWritten, NULL) == 0
+          ? false
+          : true;
+      } else {
+        DWORD bytesWritten;
+        std::string buffer;
+        success = encodeOutputBuffer(wbuffer, buffer);
+        if (success) {
+          success = ::WriteFile(m_hOutput, buffer.c_str(),
+                                (DWORD)buffer.size(), &bytesWritten, NULL) == 0
+            ? false
+            : true;
+        }
+      }
+    }
+    m_ibuffer.clear();
+    m_obuffer.clear();
+    _setg();
+    _setp();
+    return success ? 0 : -1;
+  }
+
+  virtual int_type underflow()
+  {
+    if (this->gptr() >= this->egptr()) {
+      if (!m_hInput) {
+        _setg(true);
+        return Traits::eof();
+      }
+      if (m_isConsoleInput) {
+        // ReadConsole doesn't tell if there's more input available
+        // don't support reading more characters than this
+        wchar_t wbuffer[8192];
+        DWORD charsRead;
+        if (ReadConsoleW(m_hInput, wbuffer,
+                         (sizeof(wbuffer) / sizeof(wbuffer[0])), &charsRead,
+                         NULL) == 0 ||
+            charsRead == 0) {
+          _setg(true);
+          return Traits::eof();
+        }
+        setBuffer(std::wstring(wbuffer, charsRead), m_ibuffer);
+      } else {
+        std::wstring wbuffer;
+        std::string strbuffer;
+        DWORD bytesRead;
+        LARGE_INTEGER size;
+        if (GetFileSizeEx(m_hInput, &size) == 0) {
+          _setg(true);
+          return Traits::eof();
+        }
+        char* buffer = new char[size.LowPart];
+        while (ReadFile(m_hInput, buffer, size.LowPart, &bytesRead, NULL) ==
+               0) {
+          if (GetLastError() == ERROR_MORE_DATA) {
+            strbuffer += std::string(buffer, bytesRead);
+            continue;
+          }
+          _setg(true);
+          delete[] buffer;
+          return Traits::eof();
+        }
+        if (bytesRead > 0) {
+          strbuffer += std::string(buffer, bytesRead);
+        }
+        delete[] buffer;
+        if (!decodeInputBuffer(strbuffer, wbuffer)) {
+          _setg(true);
+          return Traits::eof();
+        }
+        setBuffer(wbuffer, m_ibuffer);
+      }
+      _setg();
+    }
+    return Traits::to_int_type(*this->gptr());
+  }
+
+  virtual int_type overflow(int_type ch = Traits::eof())
+  {
+    if (!Traits::eq_int_type(ch, Traits::eof())) {
+      char_type chr = Traits::to_char_type(ch);
+      m_obuffer += chr;
+      if ((flush_on_newline && Traits::eq(chr, '\n')) ||
+          Traits::eq_int_type(ch, 0x00)) {
+        sync();
+      }
+      return ch;
+    }
+    sync();
+    return Traits::eof();
+  }
+
+public:
+  bool flush_on_newline;
+  UINT input_pipe_codepage;
+  UINT output_pipe_codepage;
+  UINT input_file_codepage;
+  UINT output_file_codepage;
+
+private:
+  HANDLE m_hInput;
+  HANDLE m_hOutput;
+  std::basic_string<char_type> m_ibuffer;
+  std::basic_string<char_type> m_obuffer;
+  bool m_isConsoleInput;
+  bool m_isConsoleOutput;
+  UINT m_activeInputCodepage;
+  UINT m_activeOutputCodepage;
+  UINT m_consolesCodepage;
+  void checkHandle(bool input, std::string handleName)
+  {
+    if ((input && m_hInput == INVALID_HANDLE_VALUE) ||
+        (!input && m_hOutput == INVALID_HANDLE_VALUE)) {
+      std::string errmsg =
+        "GetStdHandle(" + handleName + ") returned INVALID_HANDLE_VALUE";
+#if __cplusplus >= 201103L
+      throw std::system_error(::GetLastError(), std::system_category(),
+                              errmsg);
+#else
+      throw std::runtime_error(errmsg);
+#endif
+    }
+  }
+  UINT getConsolesCodepage()
+  {
+    if (!m_consolesCodepage) {
+      m_consolesCodepage = GetConsoleCP();
+      if (!m_consolesCodepage) {
+        m_consolesCodepage = GetACP();
+      }
+    }
+    return m_consolesCodepage;
+  }
+  bool setActiveInputCodepage()
+  {
+    m_isConsoleInput = false;
+    switch (GetFileType(m_hInput)) {
+      case FILE_TYPE_DISK:
+        m_activeInputCodepage = input_file_codepage;
+        break;
+      case FILE_TYPE_CHAR:
+        // Check for actual console.
+        DWORD consoleMode;
+        m_isConsoleInput =
+          GetConsoleMode(m_hInput, &consoleMode) == 0 ? false : true;
+        if (m_isConsoleInput) {
+          break;
+        }
+      case FILE_TYPE_PIPE:
+        m_activeInputCodepage = input_pipe_codepage;
+        break;
+      default:
+        return false;
+    }
+    if (!m_isConsoleInput && m_activeInputCodepage == 0) {
+      m_activeInputCodepage = getConsolesCodepage();
+    }
+    return true;
+  }
+  bool setActiveOutputCodepage()
+  {
+    m_isConsoleOutput = false;
+    switch (GetFileType(m_hOutput)) {
+      case FILE_TYPE_DISK:
+        m_activeOutputCodepage = output_file_codepage;
+        break;
+      case FILE_TYPE_CHAR:
+        // Check for actual console.
+        DWORD consoleMode;
+        m_isConsoleOutput =
+          GetConsoleMode(m_hOutput, &consoleMode) == 0 ? false : true;
+        if (m_isConsoleOutput) {
+          break;
+        }
+      case FILE_TYPE_PIPE:
+        m_activeOutputCodepage = output_pipe_codepage;
+        break;
+      default:
+        return false;
+    }
+    if (!m_isConsoleOutput && m_activeOutputCodepage == 0) {
+      m_activeOutputCodepage = getConsolesCodepage();
+    }
+    return true;
+  }
+  void _setg(bool empty = false)
+  {
+    if (!empty) {
+      this->setg((char_type*)m_ibuffer.data(), (char_type*)m_ibuffer.data(),
+                 (char_type*)m_ibuffer.data() + m_ibuffer.size());
+    } else {
+      this->setg((char_type*)m_ibuffer.data(),
+                 (char_type*)m_ibuffer.data() + m_ibuffer.size(),
+                 (char_type*)m_ibuffer.data() + m_ibuffer.size());
+    }
+  }
+  void _setp()
+  {
+    this->setp((char_type*)m_obuffer.data(),
+               (char_type*)m_obuffer.data() + m_obuffer.size());
+  }
+  bool encodeOutputBuffer(const std::wstring wbuffer, std::string& buffer)
+  {
+    if (wbuffer.size() == 0) {
+      buffer = std::string();
+      return true;
+    }
+    const int length =
+      WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(),
+                          (int)wbuffer.size(), NULL, 0, NULL, NULL);
+    char* buf = new char[length];
+    const bool success =
+      WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(),
+                          (int)wbuffer.size(), buf, length, NULL, NULL) > 0
+      ? true
+      : false;
+    buffer = std::string(buf, length);
+    delete[] buf;
+    return success;
+  }
+  bool decodeInputBuffer(const std::string buffer, std::wstring& wbuffer)
+  {
+    int length = int(buffer.length());
+    if (length == 0) {
+      wbuffer = std::wstring();
+      return true;
+    }
+    int actualCodepage = m_activeInputCodepage;
+    const char BOM_UTF8[] = { char(0xEF), char(0xBB), char(0xBF) };
+    const char* data = buffer.data();
+    const size_t BOMsize = sizeof(BOM_UTF8);
+    if (length >= BOMsize && std::memcmp(data, BOM_UTF8, BOMsize) == 0) {
+      // PowerShell uses UTF-8 with BOM for pipes
+      actualCodepage = CP_UTF8;
+      data += BOMsize;
+      length -= BOMsize;
+    }
+    const int wlength =
+      MultiByteToWideChar(actualCodepage, 0, data, length, NULL, 0);
+    wchar_t* wbuf = new wchar_t[wlength];
+    const bool success =
+      MultiByteToWideChar(actualCodepage, 0, data, length, wbuf, wlength) > 0
+      ? true
+      : false;
+    wbuffer = std::wstring(wbuf, wlength);
+    delete[] wbuf;
+    return success;
+  }
+  std::wstring getBuffer(const std::basic_string<char> buffer)
+  {
+    return Encoding::ToWide(buffer);
+  }
+  std::wstring getBuffer(const std::basic_string<wchar_t> buffer)
+  {
+    return buffer;
+  }
+  void setBuffer(const std::wstring wbuffer, std::basic_string<char>& target)
+  {
+    target = Encoding::ToNarrow(wbuffer);
+  }
+  void setBuffer(const std::wstring wbuffer,
+                 std::basic_string<wchar_t>& target)
+  {
+    target = wbuffer;
+  }
+
+}; // BasicConsoleBuf class
+
+typedef BasicConsoleBuf<char> ConsoleBuf;
+typedef BasicConsoleBuf<wchar_t> WConsoleBuf;
+
+#endif
+} // KWSYS_NAMESPACE
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Copyright.txt b/thirdparty/KWSys/adios2sys/Copyright.txt
new file mode 100644
index 0000000000000000000000000000000000000000..33d7fb472665f10f0b8a83d17be87af0df73cce6
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Copyright.txt
@@ -0,0 +1,38 @@
+KWSys - Kitware System Library
+Copyright 2000-2016 Kitware, Inc. and Contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Kitware, Inc. nor the names of Contributors
+  may be used to endorse or promote products derived from this
+  software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------------
+
+The following individuals and institutions are among the Contributors:
+
+* Insight Software Consortium <insightsoftwareconsortium.org>
+
+See version control history for details of individual contributions.
diff --git a/thirdparty/KWSys/adios2sys/Directory.cxx b/thirdparty/KWSys/adios2sys/Directory.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3c31b49ebdcadcd6cc7a3775d7a4524ea3070d18
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Directory.cxx
@@ -0,0 +1,243 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Directory.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.
+#if 0
+#include "Configure.hxx.in"
+#include "Directory.hxx.in"
+#include "Encoding.hxx.in"
+#endif
+
+#include <string>
+#include <vector>
+
+namespace KWSYS_NAMESPACE {
+
+//----------------------------------------------------------------------------
+class DirectoryInternals
+{
+public:
+  // Array of Files
+  std::vector<std::string> Files;
+
+  // Path to Open'ed directory
+  std::string Path;
+};
+
+//----------------------------------------------------------------------------
+Directory::Directory()
+{
+  this->Internal = new DirectoryInternals;
+}
+
+//----------------------------------------------------------------------------
+Directory::~Directory()
+{
+  delete this->Internal;
+}
+
+//----------------------------------------------------------------------------
+unsigned long Directory::GetNumberOfFiles() const
+{
+  return static_cast<unsigned long>(this->Internal->Files.size());
+}
+
+//----------------------------------------------------------------------------
+const char* Directory::GetFile(unsigned long dindex) const
+{
+  if (dindex >= this->Internal->Files.size()) {
+    return 0;
+  }
+  return this->Internal->Files[dindex].c_str();
+}
+
+//----------------------------------------------------------------------------
+const char* Directory::GetPath() const
+{
+  return this->Internal->Path.c_str();
+}
+
+//----------------------------------------------------------------------------
+void Directory::Clear()
+{
+  this->Internal->Path.resize(0);
+  this->Internal->Files.clear();
+}
+
+} // namespace KWSYS_NAMESPACE
+
+// First Windows platforms
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// Wide function names can vary depending on compiler:
+#ifdef __BORLANDC__
+#define _wfindfirst_func __wfindfirst
+#define _wfindnext_func __wfindnext
+#else
+#define _wfindfirst_func _wfindfirst
+#define _wfindnext_func _wfindnext
+#endif
+
+namespace KWSYS_NAMESPACE {
+
+bool Directory::Load(const std::string& name)
+{
+  this->Clear();
+#if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__)
+  // Older Visual C++ and Embarcadero compilers.
+  long srchHandle;
+#else // Newer Visual C++
+  intptr_t srchHandle;
+#endif
+  char* buf;
+  size_t n = name.size();
+  if (*name.rbegin() == '/' || *name.rbegin() == '\\') {
+    buf = new char[n + 1 + 1];
+    sprintf(buf, "%s*", name.c_str());
+  } else {
+    // Make sure the slashes in the wildcard suffix are consistent with the
+    // rest of the path
+    buf = new char[n + 2 + 1];
+    if (name.find('\\') != name.npos) {
+      sprintf(buf, "%s\\*", name.c_str());
+    } else {
+      sprintf(buf, "%s/*", name.c_str());
+    }
+  }
+  struct _wfinddata_t data; // data of current file
+
+  // Now put them into the file array
+  srchHandle =
+    _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data);
+  delete[] buf;
+
+  if (srchHandle == -1) {
+    return 0;
+  }
+
+  // Loop through names
+  do {
+    this->Internal->Files.push_back(Encoding::ToNarrow(data.name));
+  } while (_wfindnext_func(srchHandle, &data) != -1);
+  this->Internal->Path = name;
+  return _findclose(srchHandle) != -1;
+}
+
+unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
+{
+#if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__)
+  // Older Visual C++ and Embarcadero compilers.
+  long srchHandle;
+#else // Newer Visual C++
+  intptr_t srchHandle;
+#endif
+  char* buf;
+  size_t n = name.size();
+  if (*name.rbegin() == '/') {
+    buf = new char[n + 1 + 1];
+    sprintf(buf, "%s*", name.c_str());
+  } else {
+    buf = new char[n + 2 + 1];
+    sprintf(buf, "%s/*", name.c_str());
+  }
+  struct _wfinddata_t data; // data of current file
+
+  // Now put them into the file array
+  srchHandle =
+    _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data);
+  delete[] buf;
+
+  if (srchHandle == -1) {
+    return 0;
+  }
+
+  // Loop through names
+  unsigned long count = 0;
+  do {
+    count++;
+  } while (_wfindnext_func(srchHandle, &data) != -1);
+  _findclose(srchHandle);
+  return count;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#else
+
+// Now the POSIX style directory access
+
+#include <sys/types.h>
+
+#include <dirent.h>
+
+// PGI with glibc has trouble with dirent and large file support:
+//  http://www.pgroup.com/userforum/viewtopic.php?
+//  p=1992&sid=f16167f51964f1a68fe5041b8eb213b6
+// Work around the problem by mapping dirent the same way as readdir.
+#if defined(__PGI) && defined(__GLIBC__)
+#define kwsys_dirent_readdir dirent
+#define kwsys_dirent_readdir64 dirent64
+#define kwsys_dirent kwsys_dirent_lookup(readdir)
+#define kwsys_dirent_lookup(x) kwsys_dirent_lookup_delay(x)
+#define kwsys_dirent_lookup_delay(x) kwsys_dirent_##x
+#else
+#define kwsys_dirent dirent
+#endif
+
+namespace KWSYS_NAMESPACE {
+
+bool Directory::Load(const std::string& name)
+{
+  this->Clear();
+
+  DIR* dir = opendir(name.c_str());
+
+  if (!dir) {
+    return 0;
+  }
+
+  for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) {
+    this->Internal->Files.push_back(d->d_name);
+  }
+  this->Internal->Path = name;
+  closedir(dir);
+  return 1;
+}
+
+unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
+{
+  DIR* dir = opendir(name.c_str());
+
+  if (!dir) {
+    return 0;
+  }
+
+  unsigned long count = 0;
+  for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) {
+    count++;
+  }
+  closedir(dir);
+  return count;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Directory.hxx.in b/thirdparty/KWSys/adios2sys/Directory.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..ad8c51b86e29d5eb837b23e68cb0e1085a2b0a41
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Directory.hxx.in
@@ -0,0 +1,72 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Directory_hxx
+#define @KWSYS_NAMESPACE@_Directory_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+#include <string>
+
+namespace @KWSYS_NAMESPACE@ {
+
+class DirectoryInternals;
+
+/** \class Directory
+ * \brief Portable directory/filename traversal.
+ *
+ * Directory provides a portable way of finding the names of the files
+ * in a system directory.
+ *
+ * Directory currently works with Windows and Unix operating systems.
+ */
+class @KWSYS_NAMESPACE@_EXPORT Directory
+{
+public:
+  Directory();
+  ~Directory();
+
+  /**
+   * Load the specified directory and load the names of the files
+   * in that directory. 0 is returned if the directory can not be
+   * opened, 1 if it is opened.
+   */
+  bool Load(const std::string&);
+
+  /**
+   * Return the number of files in the current directory.
+   */
+  unsigned long GetNumberOfFiles() const;
+
+  /**
+   * Return the number of files in the specified directory.
+   * A higher performance static method.
+   */
+  static unsigned long GetNumberOfFilesInDirectory(const std::string&);
+
+  /**
+   * Return the file at the given index, the indexing is 0 based
+   */
+  const char* GetFile(unsigned long) const;
+
+  /**
+   * Return the path to Open'ed directory
+   */
+  const char* GetPath() const;
+
+  /**
+   * Clear the internal structure. Used internally at beginning of Load(...)
+   * to clear the cache.
+   */
+  void Clear();
+
+private:
+  // Private implementation details.
+  DirectoryInternals* Internal;
+
+  Directory(const Directory&);      // Not implemented.
+  void operator=(const Directory&); // Not implemented.
+};                                  // End Class: Directory
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/DynamicLoader.cxx b/thirdparty/KWSys/adios2sys/DynamicLoader.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e494db69c8efccab9327290d7c3063b3b4ee074e
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/DynamicLoader.cxx
@@ -0,0 +1,484 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(DynamicLoader.hxx)
+
+#include KWSYS_HEADER(Configure.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Configure.hxx.in"
+#include "DynamicLoader.hxx.in"
+#endif
+
+// This file actually contains several different implementations:
+// * NOOP for environments without dynamic libs
+// * HP machines which uses shl_load
+// * Mac OS X 10.2.x and earlier which uses NSLinkModule
+// * Windows which uses LoadLibrary
+// * BeOS / Haiku
+// * FreeMiNT for Atari
+// * Default implementation for *NIX systems (including Mac OS X 10.3 and
+//   later) which use dlopen
+//
+// Each part of the ifdef contains a complete implementation for
+// the static methods of DynamicLoader.
+
+#if !KWSYS_SUPPORTS_SHARED_LIBS
+//----------------------------------------------------------------------------
+// Implementation for environments without dynamic libs
+#include <string.h> // for strerror()
+
+namespace KWSYS_NAMESPACE {
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  return 0;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+  if (!lib) {
+    return 0;
+  }
+
+  return 1;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+  DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+  return 0;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+  return "General error";
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#elif defined(__hpux)
+//----------------------------------------------------------------------------
+// Implementation for HPUX  machines
+#include <dl.h>
+#include <errno.h>
+
+namespace KWSYS_NAMESPACE {
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+  if (!lib) {
+    return 0;
+  }
+  return !shl_unload(lib);
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+  DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+  void* addr;
+  int status;
+
+  /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
+   * TYPE_DATA      Look for a symbol in the data segment (for example,
+   * variables).
+   * TYPE_UNDEFINED Look for any symbol.
+   */
+  status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
+  void* result = (status < 0) ? (void*)0 : addr;
+
+  // Hack to cast pointer-to-data to pointer-to-function.
+  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+}
+
+const char* DynamicLoader::LastError()
+{
+  // TODO: Need implementation with errno/strerror
+  /* If successful, shl_findsym returns an integer (int) value zero. If
+   * shl_findsym cannot find sym, it returns -1 and sets errno to zero.
+   * If any other errors occur, shl_findsym returns -1 and sets errno to one
+   * of these values (defined in <errno.h>):
+   * ENOEXEC
+   * A format error was detected in the specified library.
+   * ENOSYM
+   * A symbol on which sym depends could not be found.
+   * EINVAL
+   * The specified handle is invalid.
+   */
+
+  if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) {
+    return strerror(errno);
+  }
+  // else
+  return 0;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030)
+//----------------------------------------------------------------------------
+// Implementation for Mac OS X 10.2.x and earlier
+#include <mach-o/dyld.h>
+#include <string.h> // for strlen
+
+namespace KWSYS_NAMESPACE {
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  NSObjectFileImageReturnCode rc;
+  NSObjectFileImage image = 0;
+
+  rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
+  // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
+  if (rc != NSObjectFileImageSuccess) {
+    return 0;
+  }
+  NSModule handle =
+    NSLinkModule(image, libname.c_str(), NSLINKMODULE_OPTION_BINDNOW |
+                   NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+  NSDestroyObjectFileImage(image);
+  return handle;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+  // NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED
+  // With  this  option  the memory for the module is not deallocated
+  // allowing pointers into the module to still be valid.
+  // You should use this option instead if your code experience some problems
+  // reported against Panther 10.3.9 (fixed in Tiger 10.4.2 and up)
+  bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE);
+  return success;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+  DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+  void* result = 0;
+  // Need to prepend symbols with '_' on Apple-gcc compilers
+  size_t len = sym.size();
+  char* rsym = new char[len + 1 + 1];
+  strcpy(rsym, "_");
+  strcat(rsym + 1, sym.c_str());
+
+  NSSymbol symbol = NSLookupSymbolInModule(lib, rsym);
+  if (symbol) {
+    result = NSAddressOfSymbol(symbol);
+  }
+
+  delete[] rsym;
+  // Hack to cast pointer-to-data to pointer-to-function.
+  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+  return 0;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+//----------------------------------------------------------------------------
+// Implementation for Windows win32 code but not cygwin
+#include <windows.h>
+
+namespace KWSYS_NAMESPACE {
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  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;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+  return (int)FreeLibrary(lib);
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+  DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+  // TODO: The calling convention affects the name of the symbol.  We
+  // should have a tool to help get the symbol with the desired
+  // calling convention.  Currently we assume cdecl.
+  //
+  // Borland:
+  //   __cdecl    = "_func" (default)
+  //   __fastcall = "@_func"
+  //   __stdcall  = "func"
+  //
+  // Watcom:
+  //   __cdecl    = "_func"
+  //   __fastcall = "@_func@X"
+  //   __stdcall  = "_func@X"
+  //   __watcall  = "func_" (default)
+  //
+  // MSVC:
+  //   __cdecl    = "func" (default)
+  //   __fastcall = "@_func@X"
+  //   __stdcall  = "_func@X"
+  //
+  // Note that the "@X" part of the name above is the total size (in
+  // bytes) of the arguments on the stack.
+  void* result;
+#if defined(__BORLANDC__) || defined(__WATCOMC__)
+  // Need to prepend symbols with '_'
+  size_t len = sym.size();
+  char* rsym = new char[len + 1 + 1];
+  strcpy(rsym, "_");
+  strcat(rsym, sym.c_str());
+#else
+  const char* rsym = sym.c_str();
+#endif
+  result = (void*)GetProcAddress(lib, rsym);
+#if defined(__BORLANDC__) || defined(__WATCOMC__)
+  delete[] rsym;
+#endif
+// Hack to cast pointer-to-data to pointer-to-function.
+#ifdef __WATCOMC__
+  return *(DynamicLoader::SymbolPointer*)(&result);
+#else
+  return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
+#endif
+}
+
+//----------------------------------------------------------------------------
+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);
+
+  if (!lpMsgBuf) {
+    return NULL;
+  }
+
+  static char* str = 0;
+  delete[] str;
+  str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
+  // Free the buffer.
+  LocalFree(lpMsgBuf);
+  return str;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#elif defined(__BEOS__)
+//----------------------------------------------------------------------------
+// Implementation for BeOS / Haiku
+#include <string.h> // for strerror()
+
+#include <be/kernel/image.h>
+#include <be/support/Errors.h>
+
+namespace KWSYS_NAMESPACE {
+
+static image_id last_dynamic_err = B_OK;
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  // 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());
+  if (rc < 0) {
+    last_dynamic_err = rc;
+    return 0;
+  }
+
+  return rc + 1;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+  if (!lib) {
+    last_dynamic_err = B_BAD_VALUE;
+    return 0;
+  } else {
+    // The function dlclose() returns 0 on success, and non-zero on error.
+    status_t rc = unload_add_on(lib - 1);
+    if (rc != B_OK) {
+      last_dynamic_err = rc;
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+  DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+  // Hack to cast pointer-to-data to pointer-to-function.
+  union
+  {
+    void* pvoid;
+    DynamicLoader::SymbolPointer psym;
+  } result;
+
+  result.psym = NULL;
+
+  if (!lib) {
+    last_dynamic_err = B_BAD_VALUE;
+  } else {
+    // !!! FIXME: BeOS can do function-only lookups...does this ever
+    // !!! FIXME:  actually _want_ a data symbol lookup, or was this union
+    // !!! FIXME:  a leftover of dlsym()? (s/ANY/TEXT for functions only).
+    status_t rc =
+      get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid);
+    if (rc != B_OK) {
+      last_dynamic_err = rc;
+      result.psym = NULL;
+    }
+  }
+  return result.psym;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+  const char* retval = strerror(last_dynamic_err);
+  last_dynamic_err = B_OK;
+  return retval;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#elif defined(__MINT__)
+//----------------------------------------------------------------------------
+// Implementation for FreeMiNT on Atari
+#define _GNU_SOURCE /* for program_invocation_name */
+#include <dld.h>
+#include <errno.h>
+#include <malloc.h>
+#include <string.h>
+
+namespace KWSYS_NAMESPACE {
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  char* name = (char*)calloc(1, libname.size() + 1);
+  dld_init(program_invocation_name);
+  strncpy(name, libname.c_str(), libname.size());
+  dld_link(libname.c_str());
+  return (void*)name;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+  dld_unlink_by_file((char*)lib, 0);
+  free(lib);
+  return 0;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+  DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+  // Hack to cast pointer-to-data to pointer-to-function.
+  union
+  {
+    void* pvoid;
+    DynamicLoader::SymbolPointer psym;
+  } result;
+  result.pvoid = dld_get_symbol(sym.c_str());
+  return result.psym;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+  return dld_strerror(dld_errno);
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#else
+//----------------------------------------------------------------------------
+// Default implementation for *NIX systems (including Mac OS X 10.3 and
+// later) which use dlopen
+#include <dlfcn.h>
+
+namespace KWSYS_NAMESPACE {
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  return dlopen(libname.c_str(), RTLD_LAZY);
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+  if (lib) {
+    // The function dlclose() returns 0 on success, and non-zero on error.
+    return !dlclose(lib);
+  }
+  // else
+  return 0;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+  DynamicLoader::LibraryHandle lib, const std::string& sym)
+{
+  // Hack to cast pointer-to-data to pointer-to-function.
+  union
+  {
+    void* pvoid;
+    DynamicLoader::SymbolPointer psym;
+  } result;
+  result.pvoid = dlsym(lib, sym.c_str());
+  return result.psym;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+  return dlerror();
+}
+
+} // namespace KWSYS_NAMESPACE
+#endif
diff --git a/thirdparty/KWSys/adios2sys/DynamicLoader.hxx.in b/thirdparty/KWSys/adios2sys/DynamicLoader.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..7e71a4593c6e5f07d702de20f53b067273be2f0b
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/DynamicLoader.hxx.in
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_DynamicLoader_hxx
+#define @KWSYS_NAMESPACE@_DynamicLoader_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+
+#if defined(__hpux)
+#include <dl.h>
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#elif defined(__APPLE__)
+#include <AvailabilityMacros.h>
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+#include <mach-o/dyld.h>
+#endif
+#elif defined(__BEOS__)
+#include <be/kernel/image.h>
+#endif
+
+namespace @KWSYS_NAMESPACE@ {
+/** \class DynamicLoader
+ * \brief Portable loading of dynamic libraries or dll's.
+ *
+ * DynamicLoader provides a portable interface to loading dynamic
+ * libraries or dll's into a process.
+ *
+ * Directory currently works with Windows, Apple, HP-UX and Unix (POSIX)
+ * operating systems
+ *
+ * \warning dlopen on *nix system works the following way:
+ * If filename contains a slash ("/"), then it is interpreted as a (relative
+ * or absolute) pathname.  Otherwise, the dynamic linker searches for the
+ * library as follows : see ld.so(8) for further details):
+ * Whereas this distinction does not exist on Win32. Therefore ideally you
+ * should be doing full path to garantee to have a consistent way of dealing
+ * with dynamic loading of shared library.
+ *
+ * \warning the Cygwin implementation do not use the Win32 HMODULE. Put extra
+ * condition so that we can include the correct declaration (POSIX)
+ */
+
+class @KWSYS_NAMESPACE@_EXPORT DynamicLoader
+{
+public:
+// Ugly stuff for library handles
+// They are different on several different OS's
+#if defined(__hpux)
+  typedef shl_t LibraryHandle;
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+  typedef HMODULE LibraryHandle;
+#elif defined(__APPLE__)
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+  typedef NSModule LibraryHandle;
+#else
+  typedef void* LibraryHandle;
+#endif
+#elif defined(__BEOS__)
+  typedef image_id LibraryHandle;
+#else // POSIX
+  typedef void* LibraryHandle;
+#endif
+
+  // Return type from DynamicLoader::GetSymbolAddress.
+  typedef void (*SymbolPointer)();
+
+  /** Load a dynamic library into the current process.
+   * The returned LibraryHandle can be used to access the symbols in the
+   * library. */
+  static LibraryHandle OpenLibrary(const std::string&);
+
+  /** Attempt to detach a dynamic library from the
+   * process.  A value of true is returned if it is sucessful. */
+  static int CloseLibrary(LibraryHandle);
+
+  /** Find the address of the symbol in the given library. */
+  static SymbolPointer GetSymbolAddress(LibraryHandle, const std::string&);
+
+  /** Return the default module prefix for the current platform.  */
+  static const char* LibPrefix() { return "@KWSYS_DynamicLoader_PREFIX@"; }
+
+  /** Return the default module suffix for the current platform.  */
+  static const char* LibExtension() { return "@KWSYS_DynamicLoader_SUFFIX@"; }
+
+  /** Return the last error produced from a calls made on this class. */
+  static const char* LastError();
+}; // End Class: DynamicLoader
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Encoding.h.in b/thirdparty/KWSys/adios2sys/Encoding.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..7b6ed10f8b55b00147482a04b47a62bda74eb2db
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Encoding.h.in
@@ -0,0 +1,69 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Encoding_h
+#define @KWSYS_NAMESPACE@_Encoding_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+#include <wchar.h>
+
+/* Redefine all public interface symbol names to be in the proper
+   namespace.  These macros are used internally to kwsys only, and are
+   not visible to user code.  Use kwsysHeaderDump.pl to reproduce
+   these macros after making changes to the interface.  */
+#if !defined(KWSYS_NAMESPACE)
+#define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsysEncoding kwsys_ns(Encoding)
+#define kwsysEncoding_mbstowcs kwsys_ns(Encoding_mbstowcs)
+#define kwsysEncoding_DupToWide kwsys_ns(Encoding_DupToWide)
+#define kwsysEncoding_wcstombs kwsys_ns(Encoding_wcstombs)
+#define kwsysEncoding_DupToNarrow kwsys_ns(Encoding_DupToNarrow)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Convert a narrow string to a wide string.
+   On Windows, UTF-8 is assumed, and on other platforms,
+   the current locale is assumed.
+   */
+kwsysEXPORT size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* src,
+                                          size_t n);
+
+/* Convert a narrow string to a wide string.
+   This can return NULL if the conversion fails. */
+kwsysEXPORT wchar_t* kwsysEncoding_DupToWide(const char* src);
+
+/* Convert a wide string to a narrow string.
+   On Windows, UTF-8 is assumed, and on other platforms,
+   the current locale is assumed. */
+kwsysEXPORT size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* src,
+                                          size_t n);
+
+/* Convert a wide string to a narrow string.
+   This can return NULL if the conversion fails. */
+kwsysEXPORT char* kwsysEncoding_DupToNarrow(const wchar_t* str);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+   Otherwise, undefine them to keep the namespace clean.  */
+#if !defined(KWSYS_NAMESPACE)
+#undef kwsys_ns
+#undef kwsysEXPORT
+#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#undef kwsysEncoding
+#undef kwsysEncoding_mbstowcs
+#undef kwsysEncoding_DupToWide
+#undef kwsysEncoding_wcstombs
+#undef kwsysEncoding_DupToNarrow
+#endif
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Encoding.hxx.in b/thirdparty/KWSys/adios2sys/Encoding.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..09691fd3f4bae3e900bc54ea98655a78f03f4338
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Encoding.hxx.in
@@ -0,0 +1,78 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Encoding_hxx
+#define @KWSYS_NAMESPACE@_Encoding_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+#include <vector>
+
+namespace @KWSYS_NAMESPACE@ {
+class @KWSYS_NAMESPACE@_EXPORT Encoding
+{
+public:
+  // Container class for argc/argv.
+  class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments
+  {
+  public:
+    // On Windows, get the program command line arguments
+    // in this Encoding module's 8 bit encoding.
+    // On other platforms the given argc/argv is used, and
+    // to be consistent, should be the argc/argv from main().
+    static CommandLineArguments Main(int argc, char const* const* argv);
+
+    // Construct CommandLineArguments with the given
+    // argc/argv.  It is assumed that the string is already
+    // in the encoding used by this module.
+    CommandLineArguments(int argc, char const* const* argv);
+
+    // Construct CommandLineArguments with the given
+    // argc and wide argv.  This is useful if wmain() is used.
+    CommandLineArguments(int argc, wchar_t const* const* argv);
+    ~CommandLineArguments();
+    CommandLineArguments(const CommandLineArguments&);
+    CommandLineArguments& operator=(const CommandLineArguments&);
+
+    int argc() const;
+    char const* const* argv() const;
+
+  protected:
+    std::vector<char*> argv_;
+  };
+
+/**
+ * Convert between char and wchar_t
+ */
+
+#if @KWSYS_NAMESPACE@_STL_HAS_WSTRING
+
+  // Convert a narrow string to a wide string.
+  // On Windows, UTF-8 is assumed, and on other platforms,
+  // the current locale is assumed.
+  static std::wstring ToWide(const std::string& str);
+  static std::wstring ToWide(const char* str);
+
+  // Convert a wide string to a narrow string.
+  // On Windows, UTF-8 is assumed, and on other platforms,
+  // the current locale is assumed.
+  static std::string ToNarrow(const std::wstring& str);
+  static std::string ToNarrow(const wchar_t* str);
+
+#if defined(_WIN32)
+  /**
+   * Convert the path to an extended length path to avoid MAX_PATH length
+   * limitations on Windows. If the input is a local path the result will be
+   * prefixed with \\?\; if the input is instead a network path, the result
+   * will be prefixed with \\?\UNC\. All output will also be converted to
+   * absolute paths with Windows-style backslashes.
+   **/
+  static std::wstring ToWindowsExtendedPath(std::string const&);
+#endif
+
+#endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING
+
+}; // class Encoding
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/EncodingC.c b/thirdparty/KWSys/adios2sys/EncodingC.c
new file mode 100644
index 0000000000000000000000000000000000000000..c1315b2d533bcf3f70ef146fa92ef7340d7121a7
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/EncodingC.c
@@ -0,0 +1,72 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Encoding.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "Encoding.h.in"
+#endif
+
+#include <stdlib.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* str, size_t n)
+{
+  if (str == 0) {
+    return (size_t)-1;
+  }
+#ifdef _WIN32
+  return MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest,
+                             (int)n) -
+    1;
+#else
+  return mbstowcs(dest, str, n);
+#endif
+}
+
+wchar_t* kwsysEncoding_DupToWide(const char* str)
+{
+  wchar_t* ret = NULL;
+  size_t length = kwsysEncoding_mbstowcs(NULL, str, 0) + 1;
+  if (length > 0) {
+    ret = (wchar_t*)malloc((length) * sizeof(wchar_t));
+    if (ret) {
+      ret[0] = 0;
+      kwsysEncoding_mbstowcs(ret, str, length);
+    }
+  }
+  return ret;
+}
+
+size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* str, size_t n)
+{
+  if (str == 0) {
+    return (size_t)-1;
+  }
+#ifdef _WIN32
+  return WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest,
+                             (int)n, NULL, NULL) -
+    1;
+#else
+  return wcstombs(dest, str, n);
+#endif
+}
+
+char* kwsysEncoding_DupToNarrow(const wchar_t* str)
+{
+  char* ret = NULL;
+  size_t length = kwsysEncoding_wcstombs(0, str, 0) + 1;
+  if (length > 0) {
+    ret = (char*)malloc(length);
+    if (ret) {
+      ret[0] = 0;
+      kwsysEncoding_wcstombs(ret, str, length);
+    }
+  }
+  return ret;
+}
diff --git a/thirdparty/KWSys/adios2sys/EncodingCXX.cxx b/thirdparty/KWSys/adios2sys/EncodingCXX.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..641c0e6a8e6ad1c5b027431555ec2eab78b4256a
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/EncodingCXX.cxx
@@ -0,0 +1,277 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifdef __osf__
+#define _OSF_SOURCE
+#define _POSIX_C_SOURCE 199506L
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Encoding.hxx)
+#include KWSYS_HEADER(Encoding.h)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Encoding.h.in"
+#include "Encoding.hxx.in"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <vector>
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4786)
+#endif
+
+// Windows API.
+#if defined(_WIN32)
+#include <windows.h>
+
+#include <ctype.h>
+#include <shellapi.h>
+#endif
+
+namespace KWSYS_NAMESPACE {
+
+Encoding::CommandLineArguments Encoding::CommandLineArguments::Main(
+  int argc, char const* const* argv)
+{
+#ifdef _WIN32
+  (void)argc;
+  (void)argv;
+
+  int ac;
+  LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &ac);
+
+  std::vector<std::string> av1(ac);
+  std::vector<char const*> av2(ac);
+  for (int i = 0; i < ac; i++) {
+    av1[i] = ToNarrow(w_av[i]);
+    av2[i] = av1[i].c_str();
+  }
+  LocalFree(w_av);
+  return CommandLineArguments(ac, &av2[0]);
+#else
+  return CommandLineArguments(argc, argv);
+#endif
+}
+
+Encoding::CommandLineArguments::CommandLineArguments(int ac,
+                                                     char const* const* av)
+{
+  this->argv_.resize(ac + 1);
+  for (int i = 0; i < ac; i++) {
+    this->argv_[i] = strdup(av[i]);
+  }
+  this->argv_[ac] = 0;
+}
+
+Encoding::CommandLineArguments::CommandLineArguments(int ac,
+                                                     wchar_t const* const* av)
+{
+  this->argv_.resize(ac + 1);
+  for (int i = 0; i < ac; i++) {
+    this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]);
+  }
+  this->argv_[ac] = 0;
+}
+
+Encoding::CommandLineArguments::~CommandLineArguments()
+{
+  for (size_t i = 0; i < this->argv_.size(); i++) {
+    free(argv_[i]);
+  }
+}
+
+Encoding::CommandLineArguments::CommandLineArguments(
+  const CommandLineArguments& other)
+{
+  this->argv_.resize(other.argv_.size());
+  for (size_t i = 0; i < this->argv_.size(); i++) {
+    this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : 0;
+  }
+}
+
+Encoding::CommandLineArguments& Encoding::CommandLineArguments::operator=(
+  const CommandLineArguments& other)
+{
+  if (this != &other) {
+    size_t i;
+    for (i = 0; i < this->argv_.size(); i++) {
+      free(this->argv_[i]);
+    }
+
+    this->argv_.resize(other.argv_.size());
+    for (i = 0; i < this->argv_.size(); i++) {
+      this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : 0;
+    }
+  }
+
+  return *this;
+}
+
+int Encoding::CommandLineArguments::argc() const
+{
+  return static_cast<int>(this->argv_.size() - 1);
+}
+
+char const* const* Encoding::CommandLineArguments::argv() const
+{
+  return &this->argv_[0];
+}
+
+#if KWSYS_STL_HAS_WSTRING
+
+std::wstring Encoding::ToWide(const std::string& str)
+{
+  std::wstring wstr;
+#if defined(_WIN32)
+  const int wlength = MultiByteToWideChar(
+    KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), int(str.size()), NULL, 0);
+  if (wlength > 0) {
+    wchar_t* wdata = new wchar_t[wlength];
+    int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
+                                int(str.size()), wdata, wlength);
+    if (r > 0) {
+      wstr = std::wstring(wdata, wlength);
+    }
+    delete[] wdata;
+  }
+#else
+  size_t pos = 0;
+  size_t nullPos = 0;
+  do {
+    if (pos < str.size() && str.at(pos) != '\0') {
+      wstr += ToWide(str.c_str() + pos);
+    }
+    nullPos = str.find('\0', pos);
+    if (nullPos != str.npos) {
+      pos = nullPos + 1;
+      wstr += wchar_t('\0');
+    }
+  } while (nullPos != str.npos);
+#endif
+  return wstr;
+}
+
+std::string Encoding::ToNarrow(const std::wstring& str)
+{
+  std::string nstr;
+#if defined(_WIN32)
+  int length =
+    WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(),
+                        int(str.size()), NULL, 0, NULL, NULL);
+  if (length > 0) {
+    char* data = new char[length];
+    int r =
+      WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(),
+                          int(str.size()), data, length, NULL, NULL);
+    if (r > 0) {
+      nstr = std::string(data, length);
+    }
+    delete[] data;
+  }
+#else
+  size_t pos = 0;
+  size_t nullPos = 0;
+  do {
+    if (pos < str.size() && str.at(pos) != '\0') {
+      nstr += ToNarrow(str.c_str() + pos);
+    }
+    nullPos = str.find(wchar_t('\0'), pos);
+    if (nullPos != str.npos) {
+      pos = nullPos + 1;
+      nstr += '\0';
+    }
+  } while (nullPos != str.npos);
+#endif
+  return nstr;
+}
+
+std::wstring Encoding::ToWide(const char* cstr)
+{
+  std::wstring wstr;
+  size_t length = kwsysEncoding_mbstowcs(0, cstr, 0) + 1;
+  if (length > 0) {
+    std::vector<wchar_t> wchars(length);
+    if (kwsysEncoding_mbstowcs(&wchars[0], cstr, length) > 0) {
+      wstr = &wchars[0];
+    }
+  }
+  return wstr;
+}
+
+std::string Encoding::ToNarrow(const wchar_t* wcstr)
+{
+  std::string str;
+  size_t length = kwsysEncoding_wcstombs(0, wcstr, 0) + 1;
+  if (length > 0) {
+    std::vector<char> chars(length);
+    if (kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0) {
+      str = &chars[0];
+    }
+  }
+  return str;
+}
+
+#if defined(_WIN32)
+// Convert local paths to UNC style paths
+std::wstring Encoding::ToWindowsExtendedPath(std::string const& source)
+{
+  std::wstring wsource = Encoding::ToWide(source);
+
+  // Resolve any relative paths
+  DWORD wfull_len;
+
+  /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that
+   * won't return a large enough buffer size if the input is too small */
+  wfull_len = GetFullPathNameW(wsource.c_str(), 0, NULL, NULL) + 3;
+  std::vector<wchar_t> wfull(wfull_len);
+  GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], NULL);
+
+  /* This should get the correct size without any extra padding from the
+   * previous size workaround. */
+  wfull_len = static_cast<DWORD>(wcslen(&wfull[0]));
+
+  if (wfull_len >= 2 && isalpha(wfull[0]) &&
+      wfull[1] == L':') { /* C:\Foo\bar\FooBar.txt */
+    return L"\\\\?\\" + std::wstring(&wfull[0]);
+  } else if (wfull_len >= 2 && wfull[0] == L'\\' &&
+             wfull[1] == L'\\') { /* Starts with \\ */
+    if (wfull_len >= 4 && wfull[2] == L'?' &&
+        wfull[3] == L'\\') { /* Starts with \\?\ */
+      if (wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' &&
+          wfull[6] == L'C' &&
+          wfull[7] == L'\\') { /* \\?\UNC\Foo\bar\FooBar.txt */
+        return std::wstring(&wfull[0]);
+      } else if (wfull_len >= 6 && isalpha(wfull[4]) &&
+                 wfull[5] == L':') { /* \\?\C:\Foo\bar\FooBar.txt */
+        return std::wstring(&wfull[0]);
+      } else if (wfull_len >= 5) { /* \\?\Foo\bar\FooBar.txt */
+        return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]);
+      }
+    } else if (wfull_len >= 4 && wfull[2] == L'.' &&
+               wfull[3] == L'\\') { /* Starts with \\.\ a device name */
+      if (wfull_len >= 6 && isalpha(wfull[4]) &&
+          wfull[5] == L':') { /* \\.\C:\Foo\bar\FooBar.txt */
+        return L"\\\\?\\" + std::wstring(&wfull[4]);
+      } else if (wfull_len >=
+                 5) { /* \\.\Foo\bar\ Device name is left unchanged */
+        return std::wstring(&wfull[0]);
+      }
+    } else if (wfull_len >= 3) { /* \\Foo\bar\FooBar.txt */
+      return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]);
+    }
+  }
+
+  // If this case has been reached, then the path is invalid.  Leave it
+  // unchanged
+  return Encoding::ToWide(source);
+}
+#endif
+
+#endif // KWSYS_STL_HAS_WSTRING
+
+} // namespace KWSYS_NAMESPACE
diff --git a/thirdparty/KWSys/adios2sys/ExtraTest.cmake.in b/thirdparty/KWSys/adios2sys/ExtraTest.cmake.in
new file mode 100644
index 0000000000000000000000000000000000000000..e8c0a1cdb192a6ce1dfa1540b8e42364932b32c3
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/ExtraTest.cmake.in
@@ -0,0 +1 @@
+MESSAGE("*** This message is generated by message inside a file that is included in DartTestfile.txt ***")
diff --git a/thirdparty/KWSys/adios2sys/FStream.cxx b/thirdparty/KWSys/adios2sys/FStream.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3c44a6fa01fd61d5df25d9d73a580019e711173d
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/FStream.cxx
@@ -0,0 +1,55 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(FStream.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "FStream.hxx.in"
+#endif
+
+namespace KWSYS_NAMESPACE {
+namespace FStream {
+
+BOM ReadBOM(std::istream& in)
+{
+  if (!in.good()) {
+    return BOM_None;
+  }
+  unsigned long orig = in.tellg();
+  unsigned char bom[4];
+  in.read(reinterpret_cast<char*>(bom), 2);
+  if (!in.good()) {
+    in.clear();
+    in.seekg(orig);
+    return BOM_None;
+  }
+  if (bom[0] == 0xEF && bom[1] == 0xBB) {
+    in.read(reinterpret_cast<char*>(bom + 2), 1);
+    if (in.good() && bom[2] == 0xBF) {
+      return BOM_UTF8;
+    }
+  } else if (bom[0] == 0xFE && bom[1] == 0xFF) {
+    return BOM_UTF16BE;
+  } else if (bom[0] == 0x00 && bom[1] == 0x00) {
+    in.read(reinterpret_cast<char*>(bom + 2), 2);
+    if (in.good() && bom[2] == 0xFE && bom[3] == 0xFF) {
+      return BOM_UTF32BE;
+    }
+  } else if (bom[0] == 0xFF && bom[1] == 0xFE) {
+    unsigned long p = in.tellg();
+    in.read(reinterpret_cast<char*>(bom + 2), 2);
+    if (in.good() && bom[2] == 0x00 && bom[3] == 0x00) {
+      return BOM_UTF32LE;
+    }
+    in.seekg(p);
+    return BOM_UTF16LE;
+  }
+  in.clear();
+  in.seekg(orig);
+  return BOM_None;
+}
+
+} // FStream namespace
+} // KWSYS_NAMESPACE
diff --git a/thirdparty/KWSys/adios2sys/FStream.hxx.in b/thirdparty/KWSys/adios2sys/FStream.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..d4bc6c9c729795d107a1fb7d653b3563ed0dd492
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/FStream.hxx.in
@@ -0,0 +1,276 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_FStream_hxx
+#define @KWSYS_NAMESPACE@_FStream_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <@KWSYS_NAMESPACE@/Encoding.hxx>
+
+#include <fstream>
+#if defined(_WIN32)
+#if !defined(_MSC_VER) && @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H
+#include <ext/stdio_filebuf.h>
+#endif
+#endif
+
+namespace @KWSYS_NAMESPACE@ {
+#if defined(_WIN32) &&                                                        \
+  (defined(_MSC_VER) || @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H)
+#if defined(_NOEXCEPT)
+#define @KWSYS_NAMESPACE@_FStream_NOEXCEPT _NOEXCEPT
+#else
+#define @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+#endif
+
+#if defined(_MSC_VER)
+
+template <typename CharType, typename Traits>
+class basic_filebuf : public std::basic_filebuf<CharType, Traits>
+{
+#if _MSC_VER >= 1400
+public:
+  typedef std::basic_filebuf<CharType, Traits> my_base_type;
+  basic_filebuf* open(char const* s, std::ios_base::openmode mode)
+  {
+    const std::wstring wstr = Encoding::ToWide(s);
+    return static_cast<basic_filebuf*>(my_base_type::open(wstr.c_str(), mode));
+  }
+#endif
+};
+
+#else
+
+inline std::wstring getcmode(const std::ios_base::openmode mode)
+{
+  std::wstring cmode;
+  bool plus = false;
+  if (mode & std::ios_base::app) {
+    cmode += L"a";
+    plus = mode & std::ios_base::in ? true : false;
+  } else if (mode & std::ios_base::trunc ||
+             (mode & std::ios_base::out && (mode & std::ios_base::in) == 0)) {
+    cmode += L"w";
+    plus = mode & std::ios_base::in ? true : false;
+  } else {
+    cmode += L"r";
+    plus = mode & std::ios_base::out ? true : false;
+  }
+  if (plus) {
+    cmode += L"+";
+  }
+  if (mode & std::ios_base::binary) {
+    cmode += L"b";
+  } else {
+    cmode += L"t";
+  }
+  return cmode;
+};
+
+#endif
+
+template <typename CharType, typename Traits = std::char_traits<CharType> >
+class basic_efilebuf
+{
+public:
+#if defined(_MSC_VER)
+  typedef basic_filebuf<CharType, Traits> internal_buffer_type;
+#else
+  typedef __gnu_cxx::stdio_filebuf<CharType, Traits> internal_buffer_type;
+#endif
+
+  basic_efilebuf()
+    : file_(0)
+  {
+    buf_ = 0;
+  }
+
+  bool _open(char const* file_name, std::ios_base::openmode mode)
+  {
+    if (is_open() || file_) {
+      return false;
+    }
+#if defined(_MSC_VER)
+    const bool success = buf_->open(file_name, mode) != 0;
+#else
+    const std::wstring wstr = Encoding::ToWide(file_name);
+    bool success = false;
+    std::wstring cmode = getcmode(mode);
+    file_ = _wfopen(wstr.c_str(), cmode.c_str());
+    if (file_) {
+      if (buf_) {
+        delete buf_;
+      }
+      buf_ = new internal_buffer_type(file_, mode);
+      success = true;
+    }
+#endif
+    return success;
+  }
+
+  bool is_open()
+  {
+    if (!buf_) {
+      return false;
+    }
+    return buf_->is_open();
+  }
+
+  bool is_open() const
+  {
+    if (!buf_) {
+      return false;
+    }
+    return buf_->is_open();
+  }
+
+  bool _close()
+  {
+    bool success = false;
+    if (buf_) {
+      success = buf_->close() != 0;
+#if !defined(_MSC_VER)
+      if (file_) {
+        success = fclose(file_) == 0 ? success : false;
+        file_ = 0;
+      }
+#endif
+    }
+    return success;
+  }
+
+  static void _set_state(bool success, std::basic_ios<CharType, Traits>* ios,
+                         basic_efilebuf* efilebuf)
+  {
+#if !defined(_MSC_VER)
+    ios->rdbuf(efilebuf->buf_);
+#else
+    static_cast<void>(efilebuf);
+#endif
+    if (!success) {
+      ios->setstate(std::ios_base::failbit);
+    } else {
+      ios->clear();
+    }
+  }
+
+  ~basic_efilebuf()
+  {
+    if (buf_) {
+      delete buf_;
+    }
+  }
+
+protected:
+  internal_buffer_type* buf_;
+  FILE* file_;
+};
+
+template <typename CharType, typename Traits = std::char_traits<CharType> >
+class basic_ifstream : public std::basic_istream<CharType, Traits>,
+                       public basic_efilebuf<CharType, Traits>
+{
+public:
+  typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type
+    internal_buffer_type;
+  typedef std::basic_istream<CharType, Traits> internal_stream_type;
+
+  basic_ifstream()
+    : internal_stream_type(new internal_buffer_type())
+  {
+    this->buf_ =
+      static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
+  }
+  explicit basic_ifstream(char const* file_name,
+                          std::ios_base::openmode mode = std::ios_base::in)
+    : internal_stream_type(new internal_buffer_type())
+  {
+    this->buf_ =
+      static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
+    open(file_name, mode);
+  }
+
+  void open(char const* file_name,
+            std::ios_base::openmode mode = std::ios_base::in)
+  {
+    mode = mode | std::ios_base::in;
+    this->_set_state(this->_open(file_name, mode), this, this);
+  }
+
+  void close() { this->_set_state(this->_close(), this, this); }
+
+  using basic_efilebuf<CharType, Traits>::is_open;
+
+  internal_buffer_type* rdbuf() const { return this->buf_; }
+
+  ~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); }
+};
+
+template <typename CharType, typename Traits = std::char_traits<CharType> >
+class basic_ofstream : public std::basic_ostream<CharType, Traits>,
+                       public basic_efilebuf<CharType, Traits>
+{
+  using basic_efilebuf<CharType, Traits>::is_open;
+
+public:
+  typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type
+    internal_buffer_type;
+  typedef std::basic_ostream<CharType, Traits> internal_stream_type;
+
+  basic_ofstream()
+    : internal_stream_type(new internal_buffer_type())
+  {
+    this->buf_ =
+      static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
+  }
+  explicit basic_ofstream(char const* file_name,
+                          std::ios_base::openmode mode = std::ios_base::out)
+    : internal_stream_type(new internal_buffer_type())
+  {
+    this->buf_ =
+      static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
+    open(file_name, mode);
+  }
+  void open(char const* file_name,
+            std::ios_base::openmode mode = std::ios_base::out)
+  {
+    mode = mode | std::ios_base::out;
+    this->_set_state(this->_open(file_name, mode), this, this);
+  }
+
+  void close() { this->_set_state(this->_close(), this, this); }
+
+  internal_buffer_type* rdbuf() const { return this->buf_; }
+
+  ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); }
+};
+
+typedef basic_ifstream<char> ifstream;
+typedef basic_ofstream<char> ofstream;
+
+#undef @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+#else
+using std::ofstream;
+using std::ifstream;
+#endif
+
+namespace FStream {
+enum BOM
+{
+  BOM_None,
+  BOM_UTF8,
+  BOM_UTF16BE,
+  BOM_UTF16LE,
+  BOM_UTF32BE,
+  BOM_UTF32LE
+};
+
+// Read a BOM, if one exists.
+// If a BOM exists, the stream is advanced to after the BOM.
+// This function requires a seekable stream (but not a relative
+// seekable stream).
+@KWSYS_NAMESPACE@_EXPORT BOM ReadBOM(std::istream& in);
+}
+}
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Glob.cxx b/thirdparty/KWSys/adios2sys/Glob.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fa8760d6654e30edcfff34b62337eb406f1369f7
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Glob.cxx
@@ -0,0 +1,459 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Glob.hxx)
+
+#include KWSYS_HEADER(Configure.hxx)
+
+#include KWSYS_HEADER(RegularExpression.hxx)
+#include KWSYS_HEADER(SystemTools.hxx)
+#include KWSYS_HEADER(Directory.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Configure.hxx.in"
+#include "Directory.hxx.in"
+#include "Glob.hxx.in"
+#include "RegularExpression.hxx.in"
+#include "SystemTools.hxx.in"
+#endif
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+namespace KWSYS_NAMESPACE {
+#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
+// On Windows and apple, no difference between lower and upper case
+#define KWSYS_GLOB_CASE_INDEPENDENT
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+// Handle network paths
+#define KWSYS_GLOB_SUPPORT_NETWORK_PATHS
+#endif
+
+//----------------------------------------------------------------------------
+class GlobInternals
+{
+public:
+  std::vector<std::string> Files;
+  std::vector<kwsys::RegularExpression> Expressions;
+};
+
+//----------------------------------------------------------------------------
+Glob::Glob()
+{
+  this->Internals = new GlobInternals;
+  this->Recurse = false;
+  this->Relative = "";
+
+  this->RecurseThroughSymlinks = true;
+  // RecurseThroughSymlinks is true by default for backwards compatibility,
+  // not because it's a good idea...
+  this->FollowedSymlinkCount = 0;
+
+  // Keep separate variables for directory listing for back compatibility
+  this->ListDirs = true;
+  this->RecurseListDirs = false;
+}
+
+//----------------------------------------------------------------------------
+Glob::~Glob()
+{
+  delete this->Internals;
+}
+
+//----------------------------------------------------------------------------
+std::vector<std::string>& Glob::GetFiles()
+{
+  return this->Internals->Files;
+}
+
+//----------------------------------------------------------------------------
+std::string Glob::PatternToRegex(const std::string& pattern,
+                                 bool require_whole_string, bool preserve_case)
+{
+  // Incrementally build the regular expression from the pattern.
+  std::string regex = require_whole_string ? "^" : "";
+  std::string::const_iterator pattern_first = pattern.begin();
+  std::string::const_iterator pattern_last = pattern.end();
+  for (std::string::const_iterator i = pattern_first; i != pattern_last; ++i) {
+    int c = *i;
+    if (c == '*') {
+      // A '*' (not between brackets) matches any string.
+      // We modify this to not match slashes since the orignal glob
+      // pattern documentation was meant for matching file name
+      // components separated by slashes.
+      regex += "[^/]*";
+    } else if (c == '?') {
+      // A '?' (not between brackets) matches any single character.
+      // We modify this to not match slashes since the orignal glob
+      // pattern documentation was meant for matching file name
+      // components separated by slashes.
+      regex += "[^/]";
+    } else if (c == '[') {
+      // Parse out the bracket expression.  It begins just after the
+      // opening character.
+      std::string::const_iterator bracket_first = i + 1;
+      std::string::const_iterator bracket_last = bracket_first;
+
+      // The first character may be complementation '!' or '^'.
+      if (bracket_last != pattern_last &&
+          (*bracket_last == '!' || *bracket_last == '^')) {
+        ++bracket_last;
+      }
+
+      // If the next character is a ']' it is included in the brackets
+      // because the bracket string may not be empty.
+      if (bracket_last != pattern_last && *bracket_last == ']') {
+        ++bracket_last;
+      }
+
+      // Search for the closing ']'.
+      while (bracket_last != pattern_last && *bracket_last != ']') {
+        ++bracket_last;
+      }
+
+      // Check whether we have a complete bracket string.
+      if (bracket_last == pattern_last) {
+        // The bracket string did not end, so it was opened simply by
+        // a '[' that is supposed to be matched literally.
+        regex += "\\[";
+      } else {
+        // Convert the bracket string to its regex equivalent.
+        std::string::const_iterator k = bracket_first;
+
+        // Open the regex block.
+        regex += "[";
+
+        // A regex range complement uses '^' instead of '!'.
+        if (k != bracket_last && *k == '!') {
+          regex += "^";
+          ++k;
+        }
+
+        // Convert the remaining characters.
+        for (; k != bracket_last; ++k) {
+          // Backslashes must be escaped.
+          if (*k == '\\') {
+            regex += "\\";
+          }
+
+          // Store this character.
+          regex += *k;
+        }
+
+        // Close the regex block.
+        regex += "]";
+
+        // Jump to the end of the bracket string.
+        i = bracket_last;
+      }
+    } else {
+      // A single character matches itself.
+      int ch = c;
+      if (!(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+            ('0' <= ch && ch <= '9'))) {
+        // Escape the non-alphanumeric character.
+        regex += "\\";
+      }
+#if defined(KWSYS_GLOB_CASE_INDEPENDENT)
+      else {
+        // On case-insensitive systems file names are converted to lower
+        // case before matching.
+        if (!preserve_case) {
+          ch = tolower(ch);
+        }
+      }
+#endif
+      (void)preserve_case;
+      // Store the character.
+      regex.append(1, static_cast<char>(ch));
+    }
+  }
+
+  if (require_whole_string) {
+    regex += "$";
+  }
+  return regex;
+}
+
+//----------------------------------------------------------------------------
+bool Glob::RecurseDirectory(std::string::size_type start,
+                            const std::string& dir, GlobMessages* messages)
+{
+  kwsys::Directory d;
+  if (!d.Load(dir)) {
+    return true;
+  }
+  unsigned long cc;
+  std::string realname;
+  std::string fname;
+  for (cc = 0; cc < d.GetNumberOfFiles(); cc++) {
+    fname = d.GetFile(cc);
+    if (fname == "." || fname == "..") {
+      continue;
+    }
+
+    if (start == 0) {
+      realname = dir + fname;
+    } else {
+      realname = dir + "/" + fname;
+    }
+
+#if defined(KWSYS_GLOB_CASE_INDEPENDENT)
+    // On Windows and apple, no difference between lower and upper case
+    fname = kwsys::SystemTools::LowerCase(fname);
+#endif
+
+    bool isDir = kwsys::SystemTools::FileIsDirectory(realname);
+    bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname);
+
+    if (isDir && (!isSymLink || this->RecurseThroughSymlinks)) {
+      if (isSymLink) {
+        ++this->FollowedSymlinkCount;
+        std::string realPathErrorMessage;
+        std::string canonicalPath(
+          SystemTools::GetRealPath(dir, &realPathErrorMessage));
+
+        if (!realPathErrorMessage.empty()) {
+          if (messages) {
+            messages->push_back(Message(
+              Glob::error, "Canonical path generation from path '" + dir +
+                "' failed! Reason: '" + realPathErrorMessage + "'"));
+          }
+          return false;
+        }
+
+        if (std::find(this->VisitedSymlinks.begin(),
+                      this->VisitedSymlinks.end(),
+                      canonicalPath) == this->VisitedSymlinks.end()) {
+          if (this->RecurseListDirs) {
+            // symlinks are treated as directories
+            this->AddFile(this->Internals->Files, realname);
+          }
+
+          this->VisitedSymlinks.push_back(canonicalPath);
+          if (!this->RecurseDirectory(start + 1, realname, messages)) {
+            this->VisitedSymlinks.pop_back();
+
+            return false;
+          }
+          this->VisitedSymlinks.pop_back();
+        }
+        // else we have already visited this symlink - prevent cyclic recursion
+        else if (messages) {
+          std::string message;
+          for (std::vector<std::string>::const_iterator pathIt =
+                 std::find(this->VisitedSymlinks.begin(),
+                           this->VisitedSymlinks.end(), canonicalPath);
+               pathIt != this->VisitedSymlinks.end(); ++pathIt) {
+            message += *pathIt + "\n";
+          }
+          message += canonicalPath + "/" + fname;
+          messages->push_back(Message(Glob::cyclicRecursion, message));
+        }
+      } else {
+        if (this->RecurseListDirs) {
+          this->AddFile(this->Internals->Files, realname);
+        }
+        if (!this->RecurseDirectory(start + 1, realname, messages)) {
+          return false;
+        }
+      }
+    } else {
+      if (!this->Internals->Expressions.empty() &&
+          this->Internals->Expressions.rbegin()->find(fname)) {
+        this->AddFile(this->Internals->Files, realname);
+      }
+    }
+  }
+
+  return true;
+}
+
+//----------------------------------------------------------------------------
+void Glob::ProcessDirectory(std::string::size_type start,
+                            const std::string& dir, GlobMessages* messages)
+{
+  // std::cout << "ProcessDirectory: " << dir << std::endl;
+  bool last = (start == this->Internals->Expressions.size() - 1);
+  if (last && this->Recurse) {
+    this->RecurseDirectory(start, dir, messages);
+    return;
+  }
+
+  if (start >= this->Internals->Expressions.size()) {
+    return;
+  }
+
+  kwsys::Directory d;
+  if (!d.Load(dir)) {
+    return;
+  }
+  unsigned long cc;
+  std::string realname;
+  std::string fname;
+  for (cc = 0; cc < d.GetNumberOfFiles(); cc++) {
+    fname = d.GetFile(cc);
+    if (fname == "." || fname == "..") {
+      continue;
+    }
+
+    if (start == 0) {
+      realname = dir + fname;
+    } else {
+      realname = dir + "/" + fname;
+    }
+
+#if defined(KWSYS_GLOB_CASE_INDEPENDENT)
+    // On case-insensitive file systems convert to lower case for matching.
+    fname = kwsys::SystemTools::LowerCase(fname);
+#endif
+
+    // std::cout << "Look at file: " << fname << std::endl;
+    // std::cout << "Match: "
+    // << this->Internals->TextExpressions[start].c_str() << std::endl;
+    // std::cout << "Real name: " << realname << std::endl;
+
+    if ((!last && !kwsys::SystemTools::FileIsDirectory(realname)) ||
+        (!this->ListDirs && last &&
+         kwsys::SystemTools::FileIsDirectory(realname))) {
+      continue;
+    }
+
+    if (this->Internals->Expressions[start].find(fname)) {
+      if (last) {
+        this->AddFile(this->Internals->Files, realname);
+      } else {
+        this->ProcessDirectory(start + 1, realname, messages);
+      }
+    }
+  }
+}
+
+//----------------------------------------------------------------------------
+bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages)
+{
+  std::string cexpr;
+  std::string::size_type cc;
+  std::string expr = inexpr;
+
+  this->Internals->Expressions.clear();
+  this->Internals->Files.clear();
+
+  if (!kwsys::SystemTools::FileIsFullPath(expr)) {
+    expr = kwsys::SystemTools::GetCurrentWorkingDirectory();
+    expr += "/" + inexpr;
+  }
+  std::string fexpr = expr;
+
+  std::string::size_type skip = 0;
+  std::string::size_type last_slash = 0;
+  for (cc = 0; cc < expr.size(); cc++) {
+    if (cc > 0 && expr[cc] == '/' && expr[cc - 1] != '\\') {
+      last_slash = cc;
+    }
+    if (cc > 0 && (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') &&
+        expr[cc - 1] != '\\') {
+      break;
+    }
+  }
+  if (last_slash > 0) {
+    // std::cout << "I can skip: " << fexpr.substr(0, last_slash)
+    // << std::endl;
+    skip = last_slash;
+  }
+  if (skip == 0) {
+#if defined(KWSYS_GLOB_SUPPORT_NETWORK_PATHS)
+    // Handle network paths
+    if (expr[0] == '/' && expr[1] == '/') {
+      int cnt = 0;
+      for (cc = 2; cc < expr.size(); cc++) {
+        if (expr[cc] == '/') {
+          cnt++;
+          if (cnt == 2) {
+            break;
+          }
+        }
+      }
+      skip = int(cc + 1);
+    } else
+#endif
+      // Handle drive letters on Windows
+      if (expr[1] == ':' && expr[0] != '/') {
+      skip = 2;
+    }
+  }
+
+  if (skip > 0) {
+    expr = expr.substr(skip);
+  }
+
+  cexpr = "";
+  for (cc = 0; cc < expr.size(); cc++) {
+    int ch = expr[cc];
+    if (ch == '/') {
+      if (!cexpr.empty()) {
+        this->AddExpression(cexpr);
+      }
+      cexpr = "";
+    } else {
+      cexpr.append(1, static_cast<char>(ch));
+    }
+  }
+  if (!cexpr.empty()) {
+    this->AddExpression(cexpr);
+  }
+
+  // Handle network paths
+  if (skip > 0) {
+    this->ProcessDirectory(0, fexpr.substr(0, skip) + "/", messages);
+  } else {
+    this->ProcessDirectory(0, "/", messages);
+  }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+void Glob::AddExpression(const std::string& expr)
+{
+  this->Internals->Expressions.push_back(
+    kwsys::RegularExpression(this->PatternToRegex(expr)));
+}
+
+//----------------------------------------------------------------------------
+void Glob::SetRelative(const char* dir)
+{
+  if (!dir) {
+    this->Relative = "";
+    return;
+  }
+  this->Relative = dir;
+}
+
+//----------------------------------------------------------------------------
+const char* Glob::GetRelative()
+{
+  if (this->Relative.empty()) {
+    return 0;
+  }
+  return this->Relative.c_str();
+}
+
+//----------------------------------------------------------------------------
+void Glob::AddFile(std::vector<std::string>& files, const std::string& file)
+{
+  if (!this->Relative.empty()) {
+    files.push_back(kwsys::SystemTools::RelativePath(this->Relative, file));
+  } else {
+    files.push_back(file);
+  }
+}
+
+} // namespace KWSYS_NAMESPACE
diff --git a/thirdparty/KWSys/adios2sys/Glob.hxx.in b/thirdparty/KWSys/adios2sys/Glob.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..bd4a1761699f56cf7b5f23c69168edcd83b64d4f
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Glob.hxx.in
@@ -0,0 +1,142 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Glob_hxx
+#define @KWSYS_NAMESPACE@_Glob_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+#include <vector>
+
+namespace @KWSYS_NAMESPACE@ {
+
+class GlobInternals;
+
+/** \class Glob
+ * \brief Portable globbing searches.
+ *
+ * Globbing expressions are much simpler than regular
+ * expressions. This class will search for files using
+ * globbing expressions.
+ *
+ * Finds all files that match a given globbing expression.
+ */
+class @KWSYS_NAMESPACE@_EXPORT Glob
+{
+public:
+  enum MessageType
+  {
+    error,
+    cyclicRecursion
+  };
+
+  struct Message
+  {
+    MessageType type;
+    std::string content;
+
+    Message(MessageType t, const std::string& c)
+      : type(t)
+      , content(c)
+    {
+    }
+    Message(const Message& msg)
+      : type(msg.type)
+      , content(msg.content)
+    {
+    }
+    Message& operator=(Message const& msg)
+    {
+      this->type = msg.type;
+      this->content = msg.content;
+      return *this;
+    }
+  };
+
+  typedef std::vector<Message> GlobMessages;
+  typedef std::vector<Message>::iterator GlobMessagesIterator;
+
+public:
+  Glob();
+  ~Glob();
+
+  //! Find all files that match the pattern.
+  bool FindFiles(const std::string& inexpr, GlobMessages* messages = 0);
+
+  //! Return the list of files that matched.
+  std::vector<std::string>& GetFiles();
+
+  //! Set recurse to true to match subdirectories.
+  void RecurseOn() { this->SetRecurse(true); }
+  void RecurseOff() { this->SetRecurse(false); }
+  void SetRecurse(bool i) { this->Recurse = i; }
+  bool GetRecurse() { return this->Recurse; }
+
+  //! Set recurse through symlinks to true if recursion should traverse the
+  // linked-to directories
+  void RecurseThroughSymlinksOn() { this->SetRecurseThroughSymlinks(true); }
+  void RecurseThroughSymlinksOff() { this->SetRecurseThroughSymlinks(false); }
+  void SetRecurseThroughSymlinks(bool i) { this->RecurseThroughSymlinks = i; }
+  bool GetRecurseThroughSymlinks() { return this->RecurseThroughSymlinks; }
+
+  //! Get the number of symlinks followed through recursion
+  unsigned int GetFollowedSymlinkCount() { return this->FollowedSymlinkCount; }
+
+  //! Set relative to true to only show relative path to files.
+  void SetRelative(const char* dir);
+  const char* GetRelative();
+
+  /** Convert the given globbing pattern to a regular expression.
+      There is no way to quote meta-characters.  The
+      require_whole_string argument specifies whether the regex is
+      automatically surrounded by "^" and "$" to match the whole
+      string.  This is on by default because patterns always match
+      whole strings, but may be disabled to support concatenating
+      expressions more easily (regex1|regex2|etc).  */
+  static std::string PatternToRegex(const std::string& pattern,
+                                    bool require_whole_string = true,
+                                    bool preserve_case = false);
+
+  /** Getters and setters for enabling and disabling directory
+      listing in recursive and non recursive globbing mode.
+      If listing is enabled in recursive mode it also lists
+      directory symbolic links even if follow symlinks is enabled. */
+  void SetListDirs(bool list) { this->ListDirs = list; }
+  bool GetListDirs() const { return this->ListDirs; }
+  void SetRecurseListDirs(bool list) { this->RecurseListDirs = list; }
+  bool GetRecurseListDirs() const { return this->RecurseListDirs; }
+
+protected:
+  //! Process directory
+  void ProcessDirectory(std::string::size_type start, const std::string& dir,
+                        GlobMessages* messages);
+
+  //! Process last directory, but only when recurse flags is on. That is
+  // effectively like saying: /path/to/file/**/file
+  bool RecurseDirectory(std::string::size_type start, const std::string& dir,
+                        GlobMessages* messages);
+
+  //! Add regular expression
+  void AddExpression(const std::string& expr);
+
+  //! Add a file to the list
+  void AddFile(std::vector<std::string>& files, const std::string& file);
+
+  GlobInternals* Internals;
+  bool Recurse;
+  std::string Relative;
+  bool RecurseThroughSymlinks;
+  unsigned int FollowedSymlinkCount;
+  std::vector<std::string> VisitedSymlinks;
+  bool ListDirs;
+  bool RecurseListDirs;
+
+private:
+  Glob(const Glob&);           // Not implemented.
+  void operator=(const Glob&); // Not implemented.
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/IOStream.cxx b/thirdparty/KWSys/adios2sys/IOStream.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..01ada1f2fc5f9387d2fbea0a6d701611456411bc
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/IOStream.cxx
@@ -0,0 +1,255 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Configure.hxx)
+
+// Include the streams library.
+#include <iostream>
+#include KWSYS_HEADER(IOStream.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Configure.hxx.in"
+#include "IOStream.hxx.in"
+#endif
+
+// Implement the rest of this file only if it is needed.
+#if KWSYS_IOS_NEED_OPERATORS_LL
+
+#include <stdio.h>  // sscanf, sprintf
+#include <string.h> // memchr
+
+#if defined(_MAX_INT_DIG)
+#define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG
+#else
+#define KWSYS_IOS_INT64_MAX_DIG 32
+#endif
+
+namespace KWSYS_NAMESPACE {
+
+// Scan an input stream for an integer value.
+static int IOStreamScanStream(std::istream& is, char* buffer)
+{
+  // Prepare to write to buffer.
+  char* out = buffer;
+  char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1;
+
+  // Look for leading sign.
+  if (is.peek() == '+') {
+    *out++ = '+';
+    is.ignore();
+  } else if (is.peek() == '-') {
+    *out++ = '-';
+    is.ignore();
+  }
+
+  // Determine the base.  If not specified in the stream, try to
+  // detect it from the input.  A leading 0x means hex, and a leading
+  // 0 alone means octal.
+  int base = 0;
+  int flags = is.flags() & std::ios_base::basefield;
+  if (flags == std::ios_base::oct) {
+    base = 8;
+  } else if (flags == std::ios_base::dec) {
+    base = 10;
+  } else if (flags == std::ios_base::hex) {
+    base = 16;
+  }
+  bool foundDigit = false;
+  bool foundNonZero = false;
+  if (is.peek() == '0') {
+    foundDigit = true;
+    is.ignore();
+    if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) {
+      base = 16;
+      foundDigit = false;
+      is.ignore();
+    } else if (base == 0) {
+      base = 8;
+    }
+  }
+
+  // Determine the range of digits allowed for this number.
+  const char* digits = "0123456789abcdefABCDEF";
+  int maxDigitIndex = 10;
+  if (base == 8) {
+    maxDigitIndex = 8;
+  } else if (base == 16) {
+    maxDigitIndex = 10 + 6 + 6;
+  }
+
+  // Scan until an invalid digit is found.
+  for (; is.peek() != EOF; is.ignore()) {
+    if (memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0) {
+      if ((foundNonZero || *out != '0') && out < end) {
+        ++out;
+        foundNonZero = true;
+      }
+      foundDigit = true;
+    } else {
+      break;
+    }
+  }
+
+  // Correct the buffer contents for degenerate cases.
+  if (foundDigit && !foundNonZero) {
+    *out++ = '0';
+  } else if (!foundDigit) {
+    out = buffer;
+  }
+
+  // Terminate the string in the buffer.
+  *out = '\0';
+
+  return base;
+}
+
+// Read an integer value from an input stream.
+template <class T>
+std::istream& IOStreamScanTemplate(std::istream& is, T& value, char type)
+{
+  int state = std::ios_base::goodbit;
+
+  // Skip leading whitespace.
+  std::istream::sentry okay(is);
+
+  if (okay) {
+    try {
+      // Copy the string to a buffer and construct the format string.
+      char buffer[KWSYS_IOS_INT64_MAX_DIG];
+#if defined(_MSC_VER)
+      char format[] = "%I64_";
+      const int typeIndex = 4;
+#else
+      char format[] = "%ll_";
+      const int typeIndex = 3;
+#endif
+      switch (IOStreamScanStream(is, buffer)) {
+        case 8:
+          format[typeIndex] = 'o';
+          break;
+        case 0: // Default to decimal if not told otherwise.
+        case 10:
+          format[typeIndex] = type;
+          break;
+        case 16:
+          format[typeIndex] = 'x';
+          break;
+      };
+
+      // Use sscanf to parse the number from the buffer.
+      T result;
+      int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0;
+
+      // Set flags for resulting state.
+      if (is.peek() == EOF) {
+        state |= std::ios_base::eofbit;
+      }
+      if (!success) {
+        state |= std::ios_base::failbit;
+      } else {
+        value = result;
+      }
+    } catch (...) {
+      state |= std::ios_base::badbit;
+    }
+  }
+
+  is.setstate(std::ios_base::iostate(state));
+  return is;
+}
+
+// Print an integer value to an output stream.
+template <class T>
+std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type)
+{
+  std::ostream::sentry okay(os);
+  if (okay) {
+    try {
+      // Construct the format string.
+      char format[8];
+      char* f = format;
+      *f++ = '%';
+      if (os.flags() & std::ios_base::showpos) {
+        *f++ = '+';
+      }
+      if (os.flags() & std::ios_base::showbase) {
+        *f++ = '#';
+      }
+#if defined(_MSC_VER)
+      *f++ = 'I';
+      *f++ = '6';
+      *f++ = '4';
+#else
+      *f++ = 'l';
+      *f++ = 'l';
+#endif
+      long bflags = os.flags() & std::ios_base::basefield;
+      if (bflags == std::ios_base::oct) {
+        *f++ = 'o';
+      } else if (bflags != std::ios_base::hex) {
+        *f++ = type;
+      } else if (os.flags() & std::ios_base::uppercase) {
+        *f++ = 'X';
+      } else {
+        *f++ = 'x';
+      }
+      *f = '\0';
+
+      // Use sprintf to print to a buffer and then write the
+      // buffer to the stream.
+      char buffer[2 * KWSYS_IOS_INT64_MAX_DIG];
+      sprintf(buffer, format, value);
+      os << buffer;
+    } catch (...) {
+      os.clear(os.rdstate() | std::ios_base::badbit);
+    }
+  }
+  return os;
+}
+
+#if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+// Implement input stream operator for IOStreamSLL.
+std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value)
+{
+  return IOStreamScanTemplate(is, value, 'd');
+}
+
+// Implement input stream operator for IOStreamULL.
+std::istream& IOStreamScan(std::istream& is, IOStreamULL& value)
+{
+  return IOStreamScanTemplate(is, value, 'u');
+}
+#endif
+
+#if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+// Implement output stream operator for IOStreamSLL.
+std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value)
+{
+  return IOStreamPrintTemplate(os, value, 'd');
+}
+
+// Implement output stream operator for IOStreamULL.
+std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value)
+{
+  return IOStreamPrintTemplate(os, value, 'u');
+}
+#endif
+
+} // namespace KWSYS_NAMESPACE
+
+#else
+
+namespace KWSYS_NAMESPACE {
+
+// Create one public symbol in this object file to avoid warnings from
+// archivers.
+void IOStreamSymbolToAvoidWarning();
+void IOStreamSymbolToAvoidWarning()
+{
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#endif // KWSYS_IOS_NEED_OPERATORS_LL
diff --git a/thirdparty/KWSys/adios2sys/IOStream.hxx.in b/thirdparty/KWSys/adios2sys/IOStream.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..de3a2e634461e69ae30b53a8a0fbc10037960821
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/IOStream.hxx.in
@@ -0,0 +1,126 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_IOStream_hxx
+#define @KWSYS_NAMESPACE@_IOStream_hxx
+
+#include <iosfwd>
+
+/* Define these macros temporarily to keep the code readable.  */
+#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+
+/* Whether istream supports long long.  */
+#define @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG                           \
+  @KWSYS_IOS_HAS_ISTREAM_LONG_LONG@
+
+/* Whether ostream supports long long.  */
+#define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG                           \
+  @KWSYS_IOS_HAS_OSTREAM_LONG_LONG@
+
+/* Determine whether we need to define the streaming operators for
+   long long or __int64.  */
+#if @KWSYS_USE_LONG_LONG@
+#if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG ||                           \
+  !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+#define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1
+namespace @KWSYS_NAMESPACE@ {
+typedef long long IOStreamSLL;
+typedef unsigned long long IOStreamULL;
+}
+#endif
+#elif defined(_MSC_VER) && _MSC_VER < 1300
+#define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1
+namespace @KWSYS_NAMESPACE@ {
+typedef __int64 IOStreamSLL;
+typedef unsigned __int64 IOStreamULL;
+}
+#endif
+#if !defined(@KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL)
+#define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 0
+#endif
+
+#if @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL
+#if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG
+
+/* Input stream operator implementation functions.  */
+namespace @KWSYS_NAMESPACE@ {
+kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamSLL&);
+kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamULL&);
+}
+
+/* Provide input stream operator for long long.  */
+#if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_LONG_LONG) &&                   \
+  !defined(KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED)
+#define KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED
+#define @KWSYS_NAMESPACE@_IOS_ISTREAM_LONG_LONG_DEFINED
+inline std::istream& operator>>(std::istream& is,
+                                @KWSYS_NAMESPACE@::IOStreamSLL& value)
+{
+  return @KWSYS_NAMESPACE@::IOStreamScan(is, value);
+}
+#endif
+
+/* Provide input stream operator for unsigned long long.  */
+#if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_UNSIGNED_LONG_LONG) &&          \
+  !defined(KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED)
+#define KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED
+#define @KWSYS_NAMESPACE@_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED
+inline std::istream& operator>>(std::istream& is,
+                                @KWSYS_NAMESPACE@::IOStreamULL& value)
+{
+  return @KWSYS_NAMESPACE@::IOStreamScan(is, value);
+}
+#endif
+#endif /* !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG */
+
+#if !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+
+/* Output stream operator implementation functions.  */
+namespace @KWSYS_NAMESPACE@ {
+kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamSLL);
+kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamULL);
+}
+
+/* Provide output stream operator for long long.  */
+#if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_LONG_LONG) &&                   \
+  !defined(KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED)
+#define KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED
+#define @KWSYS_NAMESPACE@_IOS_OSTREAM_LONG_LONG_DEFINED
+inline std::ostream& operator<<(std::ostream& os,
+                                @KWSYS_NAMESPACE@::IOStreamSLL value)
+{
+  return @KWSYS_NAMESPACE@::IOStreamPrint(os, value);
+}
+#endif
+
+/* Provide output stream operator for unsigned long long.  */
+#if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_UNSIGNED_LONG_LONG) &&          \
+  !defined(KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED)
+#define KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED
+#define @KWSYS_NAMESPACE@_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED
+inline std::ostream& operator<<(std::ostream& os,
+                                @KWSYS_NAMESPACE@::IOStreamULL value)
+{
+  return @KWSYS_NAMESPACE@::IOStreamPrint(os, value);
+}
+#endif
+#endif /* !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG */
+#endif /* @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL */
+
+/* Undefine temporary macros.  */
+#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#undef kwsysEXPORT
+#endif
+
+/* If building a C++ file in kwsys itself, give the source file
+   access to the macros without a configured namespace.  */
+#if defined(KWSYS_NAMESPACE)
+#define KWSYS_IOS_HAS_ISTREAM_LONG_LONG                                       \
+  @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG
+#define KWSYS_IOS_HAS_OSTREAM_LONG_LONG                                       \
+  @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+#define KWSYS_IOS_NEED_OPERATORS_LL @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/MD5.c b/thirdparty/KWSys/adios2sys/MD5.c
new file mode 100644
index 0000000000000000000000000000000000000000..1310c6474fc6e9b96303510cd1b27aaf41ea8828
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/MD5.c
@@ -0,0 +1,504 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(MD5.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "MD5.h.in"
+#endif
+
+#include <stddef.h> /* size_t */
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memcpy, strlen */
+
+/*--------------------------------------------------------------------------*/
+
+/* This MD5 implementation has been taken from a third party.  Slight
+   modifications to the arrangement of the code have been made to put
+   it in a single source file instead of a separate header and
+   implementation file.  */
+
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wcast-align"
+#endif
+
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+        http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+        either statically or dynamically; added missing #include <string.h>
+        in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+        type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+        unsigned in ANSI C, signed in traditional"; made test program
+        self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t;  /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s
+{
+  md5_word_t count[2]; /* message length in bits, lsw first */
+  md5_word_t abcd[4];  /* digest buffer */
+  md5_byte_t buf[64];  /* accumulate block */
+} md5_state_t;
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/)
+{
+  md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
+             d = pms->abcd[3];
+  md5_word_t t;
+#if BYTE_ORDER > 0
+  /* Define storage only for big-endian CPUs. */
+  md5_word_t X[16];
+#else
+  /* Define storage for little-endian or both types of CPUs. */
+  md5_word_t xbuf[16];
+  const md5_word_t* X;
+#endif
+
+  {
+#if BYTE_ORDER == 0
+    /*
+     * Determine dynamically whether this is a big-endian or
+     * little-endian machine, since we can use a more efficient
+     * algorithm on the latter.
+     */
+    static const int w = 1;
+
+    if (*((const md5_byte_t*)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+    {
+      /*
+       * On little-endian machines, we can process properly aligned
+       * data without copying it.
+       */
+      if (!((data - (const md5_byte_t*)0) & 3)) {
+        /* data are properly aligned */
+        X = (const md5_word_t*)data;
+      } else {
+        /* not aligned */
+        memcpy(xbuf, data, 64);
+        X = xbuf;
+      }
+    }
+#endif
+#if BYTE_ORDER == 0
+    else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+    {
+      /*
+       * On big-endian machines, we must arrange the bytes in the
+       * right order.
+       */
+      const md5_byte_t* xp = data;
+      int i;
+
+#if BYTE_ORDER == 0
+      X = xbuf; /* (dynamic only) */
+#else
+#define xbuf X /* (static only) */
+#endif
+      for (i = 0; i < 16; ++i, xp += 4)
+        xbuf[i] =
+          (md5_word_t)(xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24));
+    }
+#endif
+  }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/* Round 1. */
+/* Let [abcd k s i] denote the operation
+   a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)                                             \
+  t = a + F(b, c, d) + X[k] + (Ti);                                           \
+  a = ROTATE_LEFT(t, s) + b
+  /* Do the following 16 operations. */
+  SET(a, b, c, d, 0, 7, T1);
+  SET(d, a, b, c, 1, 12, T2);
+  SET(c, d, a, b, 2, 17, T3);
+  SET(b, c, d, a, 3, 22, T4);
+  SET(a, b, c, d, 4, 7, T5);
+  SET(d, a, b, c, 5, 12, T6);
+  SET(c, d, a, b, 6, 17, T7);
+  SET(b, c, d, a, 7, 22, T8);
+  SET(a, b, c, d, 8, 7, T9);
+  SET(d, a, b, c, 9, 12, T10);
+  SET(c, d, a, b, 10, 17, T11);
+  SET(b, c, d, a, 11, 22, T12);
+  SET(a, b, c, d, 12, 7, T13);
+  SET(d, a, b, c, 13, 12, T14);
+  SET(c, d, a, b, 14, 17, T15);
+  SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+/* Round 2. */
+/* Let [abcd k s i] denote the operation
+     a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)                                             \
+  t = a + G(b, c, d) + X[k] + (Ti);                                           \
+  a = ROTATE_LEFT(t, s) + b
+  /* Do the following 16 operations. */
+  SET(a, b, c, d, 1, 5, T17);
+  SET(d, a, b, c, 6, 9, T18);
+  SET(c, d, a, b, 11, 14, T19);
+  SET(b, c, d, a, 0, 20, T20);
+  SET(a, b, c, d, 5, 5, T21);
+  SET(d, a, b, c, 10, 9, T22);
+  SET(c, d, a, b, 15, 14, T23);
+  SET(b, c, d, a, 4, 20, T24);
+  SET(a, b, c, d, 9, 5, T25);
+  SET(d, a, b, c, 14, 9, T26);
+  SET(c, d, a, b, 3, 14, T27);
+  SET(b, c, d, a, 8, 20, T28);
+  SET(a, b, c, d, 13, 5, T29);
+  SET(d, a, b, c, 2, 9, T30);
+  SET(c, d, a, b, 7, 14, T31);
+  SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+/* Round 3. */
+/* Let [abcd k s t] denote the operation
+     a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)                                             \
+  t = a + H(b, c, d) + X[k] + (Ti);                                           \
+  a = ROTATE_LEFT(t, s) + b
+  /* Do the following 16 operations. */
+  SET(a, b, c, d, 5, 4, T33);
+  SET(d, a, b, c, 8, 11, T34);
+  SET(c, d, a, b, 11, 16, T35);
+  SET(b, c, d, a, 14, 23, T36);
+  SET(a, b, c, d, 1, 4, T37);
+  SET(d, a, b, c, 4, 11, T38);
+  SET(c, d, a, b, 7, 16, T39);
+  SET(b, c, d, a, 10, 23, T40);
+  SET(a, b, c, d, 13, 4, T41);
+  SET(d, a, b, c, 0, 11, T42);
+  SET(c, d, a, b, 3, 16, T43);
+  SET(b, c, d, a, 6, 23, T44);
+  SET(a, b, c, d, 9, 4, T45);
+  SET(d, a, b, c, 12, 11, T46);
+  SET(c, d, a, b, 15, 16, T47);
+  SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+/* Round 4. */
+/* Let [abcd k s t] denote the operation
+     a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)                                             \
+  t = a + I(b, c, d) + X[k] + (Ti);                                           \
+  a = ROTATE_LEFT(t, s) + b
+  /* Do the following 16 operations. */
+  SET(a, b, c, d, 0, 6, T49);
+  SET(d, a, b, c, 7, 10, T50);
+  SET(c, d, a, b, 14, 15, T51);
+  SET(b, c, d, a, 5, 21, T52);
+  SET(a, b, c, d, 12, 6, T53);
+  SET(d, a, b, c, 3, 10, T54);
+  SET(c, d, a, b, 10, 15, T55);
+  SET(b, c, d, a, 1, 21, T56);
+  SET(a, b, c, d, 8, 6, T57);
+  SET(d, a, b, c, 15, 10, T58);
+  SET(c, d, a, b, 6, 15, T59);
+  SET(b, c, d, a, 13, 21, T60);
+  SET(a, b, c, d, 4, 6, T61);
+  SET(d, a, b, c, 11, 10, T62);
+  SET(c, d, a, b, 2, 15, T63);
+  SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+  /* Then perform the following additions. (That is increment each
+     of the four registers by the value it had before this block
+     was started.) */
+  pms->abcd[0] += a;
+  pms->abcd[1] += b;
+  pms->abcd[2] += c;
+  pms->abcd[3] += d;
+}
+
+/* Initialize the algorithm. */
+static void md5_init(md5_state_t* pms)
+{
+  pms->count[0] = pms->count[1] = 0;
+  pms->abcd[0] = 0x67452301;
+  pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+  pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+  pms->abcd[3] = 0x10325476;
+}
+
+/* Append a string to the message. */
+static void md5_append(md5_state_t* pms, const md5_byte_t* data, size_t nbytes)
+{
+  const md5_byte_t* p = data;
+  size_t left = nbytes;
+  size_t offset = (pms->count[0] >> 3) & 63;
+  md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+  if (nbytes <= 0)
+    return;
+
+  /* Update the message length. */
+  pms->count[1] += (md5_word_t)(nbytes >> 29);
+  pms->count[0] += nbits;
+  if (pms->count[0] < nbits)
+    pms->count[1]++;
+
+  /* Process an initial partial block. */
+  if (offset) {
+    size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+    memcpy(pms->buf + offset, p, copy);
+    if (offset + copy < 64)
+      return;
+    p += copy;
+    left -= copy;
+    md5_process(pms, pms->buf);
+  }
+
+  /* Process full blocks. */
+  for (; left >= 64; p += 64, left -= 64)
+    md5_process(pms, p);
+
+  /* Process a final partial block. */
+  if (left)
+    memcpy(pms->buf, p, left);
+}
+
+/* Finish the message and return the digest. */
+static void md5_finish(md5_state_t* pms, md5_byte_t digest[16])
+{
+  static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                      0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                      0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                      0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                      0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  md5_byte_t data[8];
+  int i;
+
+  /* Save the length before padding. */
+  for (i = 0; i < 8; ++i)
+    data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+  /* Pad to 56 bytes mod 64. */
+  md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+  /* Append the length. */
+  md5_append(pms, data, 8);
+  for (i = 0; i < 16; ++i)
+    digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+#pragma clang diagnostic pop
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Wrap up the MD5 state in our opaque structure.  */
+struct kwsysMD5_s
+{
+  md5_state_t md5_state;
+};
+
+/*--------------------------------------------------------------------------*/
+kwsysMD5* kwsysMD5_New(void)
+{
+  /* Allocate a process control structure.  */
+  kwsysMD5* md5 = (kwsysMD5*)malloc(sizeof(kwsysMD5));
+  if (!md5) {
+    return 0;
+  }
+  return md5;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_Delete(kwsysMD5* md5)
+{
+  /* Make sure we have an instance.  */
+  if (!md5) {
+    return;
+  }
+
+  /* Free memory.  */
+  free(md5);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_Initialize(kwsysMD5* md5)
+{
+  md5_init(&md5->md5_state);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, int length)
+{
+  size_t dlen;
+  if (length < 0) {
+    dlen = strlen((char const*)data);
+  } else {
+    dlen = (size_t)length;
+  }
+  md5_append(&md5->md5_state, (md5_byte_t const*)data, dlen);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16])
+{
+  md5_finish(&md5->md5_state, (md5_byte_t*)digest);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32])
+{
+  unsigned char digest[16];
+  kwsysMD5_Finalize(md5, digest);
+  kwsysMD5_DigestToHex(digest, buffer);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysMD5_DigestToHex(unsigned char const digest[16], char buffer[32])
+{
+  /* Map from 4-bit index to hexadecimal representation.  */
+  static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+                                '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+  /* Map each 4-bit block separately.  */
+  char* out = buffer;
+  int i;
+  for (i = 0; i < 16; ++i) {
+    *out++ = hex[digest[i] >> 4];
+    *out++ = hex[digest[i] & 0xF];
+  }
+}
diff --git a/thirdparty/KWSys/adios2sys/MD5.h.in b/thirdparty/KWSys/adios2sys/MD5.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..c257f7f9ae5314a0d22352017d7a01498ebe1512
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/MD5.h.in
@@ -0,0 +1,97 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_MD5_h
+#define @KWSYS_NAMESPACE@_MD5_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+/* Redefine all public interface symbol names to be in the proper
+   namespace.  These macros are used internally to kwsys only, and are
+   not visible to user code.  Use kwsysHeaderDump.pl to reproduce
+   these macros after making changes to the interface.  */
+#if !defined(KWSYS_NAMESPACE)
+#define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsysMD5 kwsys_ns(MD5)
+#define kwsysMD5_s kwsys_ns(MD5_s)
+#define kwsysMD5_New kwsys_ns(MD5_New)
+#define kwsysMD5_Delete kwsys_ns(MD5_Delete)
+#define kwsysMD5_Initialize kwsys_ns(MD5_Initialize)
+#define kwsysMD5_Append kwsys_ns(MD5_Append)
+#define kwsysMD5_Finalize kwsys_ns(MD5_Finalize)
+#define kwsysMD5_FinalizeHex kwsys_ns(MD5_FinalizeHex)
+#define kwsysMD5_DigestToHex kwsys_ns(MD5_DigestToHex)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * MD5 state data structure.
+ */
+typedef struct kwsysMD5_s kwsysMD5;
+
+/**
+ * Create a new MD5 instance.  The returned instance is not initialized.
+ */
+kwsysEXPORT kwsysMD5* kwsysMD5_New(void);
+
+/**
+ * Delete an old MD5 instance.
+ */
+kwsysEXPORT void kwsysMD5_Delete(kwsysMD5* md5);
+
+/**
+ * Initialize a new MD5 digest.
+ */
+kwsysEXPORT void kwsysMD5_Initialize(kwsysMD5* md5);
+
+/**
+ * Append data to an MD5 digest.  If the given length is negative,
+ * data will be read up to but not including a terminating null.
+ */
+kwsysEXPORT void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data,
+                                 int length);
+
+/**
+ * Finalize a MD5 digest and get the 16-byte hash value.
+ */
+kwsysEXPORT void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]);
+
+/**
+ * Finalize a MD5 digest and get the 32-bit hexadecimal representation.
+ */
+kwsysEXPORT void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]);
+
+/**
+ * Convert a MD5 digest 16-byte value to a 32-byte hexadecimal representation.
+ */
+kwsysEXPORT void kwsysMD5_DigestToHex(unsigned char const digest[16],
+                                      char buffer[32]);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+   Otherwise, undefine them to keep the namespace clean.  */
+#if !defined(KWSYS_NAMESPACE)
+#undef kwsys_ns
+#undef kwsysEXPORT
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#undef kwsysMD5
+#undef kwsysMD5_s
+#undef kwsysMD5_New
+#undef kwsysMD5_Delete
+#undef kwsysMD5_Initialize
+#undef kwsysMD5_Append
+#undef kwsysMD5_Finalize
+#undef kwsysMD5_FinalizeHex
+#undef kwsysMD5_DigestToHex
+#endif
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Process.h.in b/thirdparty/KWSys/adios2sys/Process.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..b8349a66a148c0a6172560ec659f0c74450420d1
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Process.h.in
@@ -0,0 +1,463 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Process_h
+#define @KWSYS_NAMESPACE@_Process_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+/* Redefine all public interface symbol names to be in the proper
+   namespace.  These macros are used internally to kwsys only, and are
+   not visible to user code.  Use kwsysHeaderDump.pl to reproduce
+   these macros after making changes to the interface.  */
+#if !defined(KWSYS_NAMESPACE)
+#define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsysProcess kwsys_ns(Process)
+#define kwsysProcess_s kwsys_ns(Process_s)
+#define kwsysProcess_New kwsys_ns(Process_New)
+#define kwsysProcess_Delete kwsys_ns(Process_Delete)
+#define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand)
+#define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand)
+#define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout)
+#define kwsysProcess_SetWorkingDirectory kwsys_ns(Process_SetWorkingDirectory)
+#define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile)
+#define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative)
+#define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared)
+#define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach)
+#define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow)
+#define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput)
+#define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim)
+#define kwsysProcess_Option_CreateProcessGroup                                \
+  kwsys_ns(Process_Option_CreateProcessGroup)
+#define kwsysProcess_GetOption kwsys_ns(Process_GetOption)
+#define kwsysProcess_SetOption kwsys_ns(Process_SetOption)
+#define kwsysProcess_Option_e kwsys_ns(Process_Option_e)
+#define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting)
+#define kwsysProcess_State_Error kwsys_ns(Process_State_Error)
+#define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception)
+#define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing)
+#define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited)
+#define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired)
+#define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed)
+#define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned)
+#define kwsysProcess_GetState kwsys_ns(Process_GetState)
+#define kwsysProcess_State_e kwsys_ns(Process_State_e)
+#define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None)
+#define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault)
+#define kwsysProcess_Exception_Illegal kwsys_ns(Process_Exception_Illegal)
+#define kwsysProcess_Exception_Interrupt kwsys_ns(Process_Exception_Interrupt)
+#define kwsysProcess_Exception_Numerical kwsys_ns(Process_Exception_Numerical)
+#define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other)
+#define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException)
+#define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e)
+#define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode)
+#define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue)
+#define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString)
+#define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString)
+#define kwsysProcess_Execute kwsys_ns(Process_Execute)
+#define kwsysProcess_Disown kwsys_ns(Process_Disown)
+#define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData)
+#define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e)
+#define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None)
+#define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN)
+#define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT)
+#define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR)
+#define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout)
+#define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle)
+#define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit)
+#define kwsysProcess_Interrupt kwsys_ns(Process_Interrupt)
+#define kwsysProcess_Kill kwsys_ns(Process_Kill)
+#define kwsysProcess_ResetStartTime kwsys_ns(Process_ResetStartTime)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Process control data structure.
+ */
+typedef struct kwsysProcess_s kwsysProcess;
+
+/* Platform-specific pipe handle type.  */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+typedef void* kwsysProcess_Pipe_Handle;
+#else
+typedef int kwsysProcess_Pipe_Handle;
+#endif
+
+/**
+ * Create a new Process instance.
+ */
+kwsysEXPORT kwsysProcess* kwsysProcess_New(void);
+
+/**
+ * Delete an existing Process instance.  If the instance is currently
+ * executing a process, this blocks until the process terminates.
+ */
+kwsysEXPORT void kwsysProcess_Delete(kwsysProcess* cp);
+
+/**
+ * Set the command line to be executed.  Argument is an array of
+ * pointers to the command and each argument.  The array must end with
+ * a NULL pointer.  Any previous command lines are removed.  Returns
+ * 1 for success and 0 otherwise.
+ */
+kwsysEXPORT int kwsysProcess_SetCommand(kwsysProcess* cp,
+                                        char const* const* command);
+
+/**
+ * Add a command line to be executed.  Argument is an array of
+ * pointers to the command and each argument.  The array must end with
+ * a NULL pointer.  If this is not the first command added, its
+ * standard input will be connected to the standard output of the
+ * previous command.  Returns 1 for success and 0 otherwise.
+ */
+kwsysEXPORT int kwsysProcess_AddCommand(kwsysProcess* cp,
+                                        char const* const* command);
+
+/**
+ * Set the timeout in seconds for the child process.  The timeout
+ * period begins when the child is executed.  If the child has not
+ * terminated when the timeout expires, it will be killed.  A
+ * non-positive (<= 0) value will disable the timeout.
+ */
+kwsysEXPORT void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout);
+
+/**
+ * Set the working directory for the child process.  The working
+ * directory can be absolute or relative to the current directory.
+ * Returns 1 for success and 0 for failure.
+ */
+kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp,
+                                                 const char* dir);
+
+/**
+ * Set the name of a file to be attached to the given pipe.  Returns 1
+ * for success and 0 for failure.
+ */
+kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe,
+                                         const char* file);
+
+/**
+ * Set whether the given pipe in the child is shared with the parent
+ * process.  The default is no for Pipe_STDOUT and Pipe_STDERR and yes
+ * for Pipe_STDIN.
+ */
+kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe,
+                                            int shared);
+
+/**
+ * Specify a platform-specific native pipe for use as one of the child
+ * interface pipes.  The native pipe is specified by an array of two
+ * descriptors or handles.  The first entry in the array (index 0)
+ * should be the read end of the pipe.  The second entry in the array
+ * (index 1) should be the write end of the pipe.  If a null pointer
+ * is given the option will be disabled.
+ *
+ * For Pipe_STDIN the native pipe is connected to the first child in
+ * the pipeline as its stdin.  After the children are created the
+ * write end of the pipe will be closed in the child process and the
+ * read end will be closed in the parent process.
+ *
+ * For Pipe_STDOUT and Pipe_STDERR the pipe is connected to the last
+ * child as its stdout or stderr.  After the children are created the
+ * write end of the pipe will be closed in the parent process and the
+ * read end will be closed in the child process.
+ */
+kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe,
+                                            kwsysProcess_Pipe_Handle p[2]);
+
+/**
+ * Get/Set a possibly platform-specific option.  Possible options are:
+ *
+ *  kwsysProcess_Option_Detach = Whether to detach the process.
+ *         0 = No (default)
+ *         1 = Yes
+ *
+ *  kwsysProcess_Option_HideWindow = Whether to hide window on Windows.
+ *         0 = No (default)
+ *         1 = Yes
+ *
+ *  kwsysProcess_Option_MergeOutput = Whether to merge stdout/stderr.
+ *                                    No content will be returned as stderr.
+ *                                    Any actual stderr will be on stdout.
+ *         0 = No (default)
+ *         1 = Yes
+ *
+ *  kwsysProcess_Option_Verbatim = Whether SetCommand and AddCommand
+ *                                 should treat the first argument
+ *                                 as a verbatim command line
+ *                                 and ignore the rest of the arguments.
+ *         0 = No (default)
+ *         1 = Yes
+ *
+ *  kwsysProcess_Option_CreateProcessGroup = Whether to place the process in a
+ *                                           new process group.  This is
+ *                                           useful if you want to send Ctrl+C
+ *                                           to the process.  On UNIX, also
+ *                                           places the process in a new
+ *                                           session.
+ *         0 = No (default)
+ *         1 = Yes
+ */
+kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId);
+kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
+                                        int value);
+enum kwsysProcess_Option_e
+{
+  kwsysProcess_Option_HideWindow,
+  kwsysProcess_Option_Detach,
+  kwsysProcess_Option_MergeOutput,
+  kwsysProcess_Option_Verbatim,
+  kwsysProcess_Option_CreateProcessGroup
+};
+
+/**
+ * Get the current state of the Process instance.  Possible states are:
+ *
+ *  kwsysProcess_State_Starting  = Execute has not yet been called.
+ *  kwsysProcess_State_Error     = Error administrating the child process.
+ *  kwsysProcess_State_Exception = Child process exited abnormally.
+ *  kwsysProcess_State_Executing = Child process is currently running.
+ *  kwsysProcess_State_Exited    = Child process exited normally.
+ *  kwsysProcess_State_Expired   = Child process's timeout expired.
+ *  kwsysProcess_State_Killed    = Child process terminated by Kill method.
+ *  kwsysProcess_State_Disowned  = Child is no longer managed by this object.
+ */
+kwsysEXPORT int kwsysProcess_GetState(kwsysProcess* cp);
+enum kwsysProcess_State_e
+{
+  kwsysProcess_State_Starting,
+  kwsysProcess_State_Error,
+  kwsysProcess_State_Exception,
+  kwsysProcess_State_Executing,
+  kwsysProcess_State_Exited,
+  kwsysProcess_State_Expired,
+  kwsysProcess_State_Killed,
+  kwsysProcess_State_Disowned
+};
+
+/**
+ * When GetState returns "Exception", this method returns a
+ * platform-independent description of the exceptional behavior that
+ * caused the child to terminate abnormally.  Possible exceptions are:
+ *
+ *  kwsysProcess_Exception_None      = No exceptional behavior occurred.
+ *  kwsysProcess_Exception_Fault     = Child crashed with a memory fault.
+ *  kwsysProcess_Exception_Illegal   = Child crashed with an illegal
+ * instruction.
+ *  kwsysProcess_Exception_Interrupt = Child was interrupted by user
+ * (Cntl-C/Break).
+ *  kwsysProcess_Exception_Numerical = Child crashed with a numerical
+ * exception.
+ *  kwsysProcess_Exception_Other     = Child terminated for another reason.
+ */
+kwsysEXPORT int kwsysProcess_GetExitException(kwsysProcess* cp);
+enum kwsysProcess_Exception_e
+{
+  kwsysProcess_Exception_None,
+  kwsysProcess_Exception_Fault,
+  kwsysProcess_Exception_Illegal,
+  kwsysProcess_Exception_Interrupt,
+  kwsysProcess_Exception_Numerical,
+  kwsysProcess_Exception_Other
+};
+
+/**
+ * When GetState returns "Exited" or "Exception", this method returns
+ * the platform-specific raw exit code of the process.  UNIX platforms
+ * should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access
+ * this value.  Windows users should compare the value to the various
+ * EXCEPTION_* values.
+ *
+ * If GetState returns "Exited", use GetExitValue to get the
+ * platform-independent child return value.
+ */
+kwsysEXPORT int kwsysProcess_GetExitCode(kwsysProcess* cp);
+
+/**
+ * When GetState returns "Exited", this method returns the child's
+ * platform-independent exit code (such as the value returned by the
+ * child's main).
+ */
+kwsysEXPORT int kwsysProcess_GetExitValue(kwsysProcess* cp);
+
+/**
+ * When GetState returns "Error", this method returns a string
+ * describing the problem.  Otherwise, it returns NULL.
+ */
+kwsysEXPORT const char* kwsysProcess_GetErrorString(kwsysProcess* cp);
+
+/**
+ * When GetState returns "Exception", this method returns a string
+ * describing the problem.  Otherwise, it returns NULL.
+ */
+kwsysEXPORT const char* kwsysProcess_GetExceptionString(kwsysProcess* cp);
+
+/**
+ * Start executing the child process.
+ */
+kwsysEXPORT void kwsysProcess_Execute(kwsysProcess* cp);
+
+/**
+ * Stop management of a detached child process.  This closes any pipes
+ * being read.  If the child was not created with the
+ * kwsysProcess_Option_Detach option, this method does nothing.  This
+ * is because disowning a non-detached process will cause the child
+ * exit signal to be left unhandled until this process exits.
+ */
+kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp);
+
+/**
+ * Block until data are available on a pipe, a timeout expires, or the
+ * child process terminates.  Arguments are as follows:
+ *
+ *  data    = If data are read, the pointer to which this points is
+ *            set to point to the data.
+ *  length  = If data are read, the integer to which this points is
+ *            set to the length of the data read.
+ *  timeout = Specifies the maximum time this call may block.  Upon
+ *            return after reading data, the time elapsed is subtracted
+ *            from the timeout value.  If this timeout expires, the
+ *            value is set to 0.  A NULL pointer passed for this argument
+ *            indicates no timeout for the call.  A negative or zero
+ *            value passed for this argument may be used for polling
+ *            and will always return immediately.
+ *
+ * Return value will be one of:
+ *
+ *   Pipe_None    = No more data will be available from the child process,
+ *    ( == 0)       or no process has been executed.  WaitForExit should
+ *                  be called to wait for the process to terminate.
+ *   Pipe_STDOUT  = Data have been read from the child's stdout pipe.
+ *   Pipe_STDERR  = Data have been read from the child's stderr pipe.
+ *   Pipe_Timeout = No data available within timeout specified for the
+ *                  call.  Time elapsed has been subtracted from timeout
+ *                  argument.
+ */
+kwsysEXPORT int kwsysProcess_WaitForData(kwsysProcess* cp, char** data,
+                                         int* length, double* timeout);
+enum kwsysProcess_Pipes_e
+{
+  kwsysProcess_Pipe_None,
+  kwsysProcess_Pipe_STDIN,
+  kwsysProcess_Pipe_STDOUT,
+  kwsysProcess_Pipe_STDERR,
+  kwsysProcess_Pipe_Timeout = 255
+};
+
+/**
+ * Block until the child process terminates or the given timeout
+ * expires.  If no process is running, returns immediatly.  The
+ * argument is:
+ *
+ *  timeout = Specifies the maximum time this call may block.  Upon
+ *            returning due to child termination, the elapsed time
+ *            is subtracted from the given value.  A NULL pointer
+ *            passed for this argument indicates no timeout for the
+ *            call.
+ *
+ * Return value will be one of:
+ *
+ *    0 = Child did not terminate within timeout specified for
+ *        the call.  Time elapsed has been subtracted from timeout
+ *        argument.
+ *    1 = Child has terminated or was not running.
+ */
+kwsysEXPORT int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout);
+
+/**
+ * Interrupt the process group for the child process that is currently
+ * running by sending it the appropriate operating-system specific signal.
+ * The caller should call WaitForExit after this returns to wait for the
+ * child to terminate.
+ *
+ * WARNING:  If you didn't specify kwsysProcess_Option_CreateProcessGroup,
+ * you will interrupt your own process group.
+ */
+kwsysEXPORT void kwsysProcess_Interrupt(kwsysProcess* cp);
+
+/**
+ * Forcefully terminate the child process that is currently running.
+ * The caller should call WaitForExit after this returns to wait for
+ * the child to terminate.
+ */
+kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
+
+/**
+ * Reset the start time of the child process to the current time.
+ */
+kwsysEXPORT void kwsysProcess_ResetStartTime(kwsysProcess* cp);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+   Otherwise, undefine them to keep the namespace clean.  */
+#if !defined(KWSYS_NAMESPACE)
+#undef kwsys_ns
+#undef kwsysEXPORT
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#undef kwsysProcess
+#undef kwsysProcess_s
+#undef kwsysProcess_New
+#undef kwsysProcess_Delete
+#undef kwsysProcess_SetCommand
+#undef kwsysProcess_AddCommand
+#undef kwsysProcess_SetTimeout
+#undef kwsysProcess_SetWorkingDirectory
+#undef kwsysProcess_SetPipeFile
+#undef kwsysProcess_SetPipeNative
+#undef kwsysProcess_SetPipeShared
+#undef kwsysProcess_Option_Detach
+#undef kwsysProcess_Option_HideWindow
+#undef kwsysProcess_Option_MergeOutput
+#undef kwsysProcess_Option_Verbatim
+#undef kwsysProcess_Option_CreateProcessGroup
+#undef kwsysProcess_GetOption
+#undef kwsysProcess_SetOption
+#undef kwsysProcess_Option_e
+#undef kwsysProcess_State_Starting
+#undef kwsysProcess_State_Error
+#undef kwsysProcess_State_Exception
+#undef kwsysProcess_State_Executing
+#undef kwsysProcess_State_Exited
+#undef kwsysProcess_State_Expired
+#undef kwsysProcess_State_Killed
+#undef kwsysProcess_State_Disowned
+#undef kwsysProcess_GetState
+#undef kwsysProcess_State_e
+#undef kwsysProcess_Exception_None
+#undef kwsysProcess_Exception_Fault
+#undef kwsysProcess_Exception_Illegal
+#undef kwsysProcess_Exception_Interrupt
+#undef kwsysProcess_Exception_Numerical
+#undef kwsysProcess_Exception_Other
+#undef kwsysProcess_GetExitException
+#undef kwsysProcess_Exception_e
+#undef kwsysProcess_GetExitCode
+#undef kwsysProcess_GetExitValue
+#undef kwsysProcess_GetErrorString
+#undef kwsysProcess_GetExceptionString
+#undef kwsysProcess_Execute
+#undef kwsysProcess_Disown
+#undef kwsysProcess_WaitForData
+#undef kwsysProcess_Pipes_e
+#undef kwsysProcess_Pipe_None
+#undef kwsysProcess_Pipe_STDIN
+#undef kwsysProcess_Pipe_STDOUT
+#undef kwsysProcess_Pipe_STDERR
+#undef kwsysProcess_Pipe_Timeout
+#undef kwsysProcess_Pipe_Handle
+#undef kwsysProcess_WaitForExit
+#undef kwsysProcess_Interrupt
+#undef kwsysProcess_Kill
+#undef kwsysProcess_ResetStartTime
+#endif
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/ProcessUNIX.c b/thirdparty/KWSys/adios2sys/ProcessUNIX.c
new file mode 100644
index 0000000000000000000000000000000000000000..ed0909543b4f3679ed7491cdb5b0fb9498745625
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/ProcessUNIX.c
@@ -0,0 +1,2895 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Process.h)
+#include KWSYS_HEADER(System.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "Process.h.in"
+#include "System.h.in"
+#endif
+
+/*
+
+Implementation for UNIX
+
+On UNIX, a child process is forked to exec the program.  Three output
+pipes are read by the parent process using a select call to block
+until data are ready.  Two of the pipes are stdout and stderr for the
+child.  The third is a special pipe populated by a signal handler to
+indicate that a child has terminated.  This is used in conjunction
+with the timeout on the select call to implement a timeout for program
+even when it closes stdout and stderr and at the same time avoiding
+races.
+
+*/
+
+/*
+
+TODO:
+
+We cannot create the pipeline of processes in suspended states.  How
+do we cleanup processes already started when one fails to load?  Right
+now we are just killing them, which is probably not the right thing to
+do.
+
+*/
+
+#if defined(__CYGWIN__)
+/* Increase the file descriptor limit for select() before including
+   related system headers. (Default: 64) */
+#define FD_SETSIZE 16384
+#endif
+
+#include <assert.h>    /* assert */
+#include <ctype.h>     /* isspace */
+#include <dirent.h>    /* DIR, dirent */
+#include <errno.h>     /* errno */
+#include <fcntl.h>     /* fcntl */
+#include <signal.h>    /* sigaction */
+#include <stddef.h>    /* ptrdiff_t */
+#include <stdio.h>     /* snprintf */
+#include <stdlib.h>    /* malloc, free */
+#include <string.h>    /* strdup, strerror, memset */
+#include <sys/stat.h>  /* open mode */
+#include <sys/time.h>  /* struct timeval */
+#include <sys/types.h> /* pid_t, fd_set */
+#include <sys/wait.h>  /* waitpid */
+#include <time.h>      /* gettimeofday */
+#include <unistd.h>    /* pipe, close, fork, execvp, select, _exit */
+
+#if defined(__VMS)
+#define KWSYSPE_VMS_NONBLOCK , O_NONBLOCK
+#else
+#define KWSYSPE_VMS_NONBLOCK
+#endif
+
+#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T
+typedef ptrdiff_t kwsysProcess_ptrdiff_t;
+#else
+typedef int kwsysProcess_ptrdiff_t;
+#endif
+
+#if defined(KWSYS_C_HAS_SSIZE_T) && KWSYS_C_HAS_SSIZE_T
+typedef ssize_t kwsysProcess_ssize_t;
+#else
+typedef int kwsysProcess_ssize_t;
+#endif
+
+#if defined(__BEOS__) && !defined(__ZETA__)
+/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
+#include <be/kernel/OS.h>
+static inline void kwsysProcess_usleep(unsigned int msec)
+{
+  snooze(msec);
+}
+#else
+#define kwsysProcess_usleep usleep
+#endif
+
+/*
+ * BeOS's select() works like WinSock: it's for networking only, and
+ * doesn't work with Unix file handles...socket and file handles are
+ * different namespaces (the same descriptor means different things in
+ * each context!)
+ *
+ * So on Unix-like systems where select() is flakey, we'll set the
+ * pipes' file handles to be non-blocking and just poll them directly
+ * without select().
+ */
+#if !defined(__BEOS__) && !defined(__VMS) && !defined(__MINT__)
+#define KWSYSPE_USE_SELECT 1
+#endif
+
+/* Some platforms do not have siginfo on their signal handlers.  */
+#if defined(SA_SIGINFO) && !defined(__BEOS__)
+#define KWSYSPE_USE_SIGINFO 1
+#endif
+
+/* The number of pipes for the child's output.  The standard stdout
+   and stderr pipes are the first two.  One more pipe is used to
+   detect when the child process has terminated.  The third pipe is
+   not given to the child process, so it cannot close it until it
+   terminates.  */
+#define KWSYSPE_PIPE_COUNT 3
+#define KWSYSPE_PIPE_STDOUT 0
+#define KWSYSPE_PIPE_STDERR 1
+#define KWSYSPE_PIPE_SIGNAL 2
+
+/* The maximum amount to read from a pipe at a time.  */
+#define KWSYSPE_PIPE_BUFFER_SIZE 1024
+
+/* Keep track of times using a signed representation.  Switch to the
+   native (possibly unsigned) representation only when calling native
+   functions.  */
+typedef struct timeval kwsysProcessTimeNative;
+typedef struct kwsysProcessTime_s kwsysProcessTime;
+struct kwsysProcessTime_s
+{
+  long tv_sec;
+  long tv_usec;
+};
+
+typedef struct kwsysProcessCreateInformation_s
+{
+  int StdIn;
+  int StdOut;
+  int StdErr;
+  int ErrorPipe[2];
+} kwsysProcessCreateInformation;
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessVolatileFree(volatile void* p);
+static int kwsysProcessInitialize(kwsysProcess* cp);
+static void kwsysProcessCleanup(kwsysProcess* cp, int error);
+static void kwsysProcessCleanupDescriptor(int* pfd);
+static void kwsysProcessClosePipes(kwsysProcess* cp);
+static int kwsysProcessSetNonBlocking(int fd);
+static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
+                              kwsysProcessCreateInformation* si);
+static void kwsysProcessDestroy(kwsysProcess* cp);
+static int kwsysProcessSetupOutputPipeFile(int* p, const char* name);
+static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]);
+static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
+                                      kwsysProcessTime* timeoutTime);
+static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
+                                      double* userTimeout,
+                                      kwsysProcessTimeNative* timeoutLength,
+                                      int zeroIsExpired);
+static kwsysProcessTime kwsysProcessTimeGetCurrent(void);
+static double kwsysProcessTimeToDouble(kwsysProcessTime t);
+static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
+static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
+static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
+                                            kwsysProcessTime in2);
+static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
+                                                 kwsysProcessTime in2);
+static void kwsysProcessSetExitException(kwsysProcess* cp, int sig);
+static void kwsysProcessChildErrorExit(int errorPipe);
+static void kwsysProcessRestoreDefaultSignalHandlers(void);
+static pid_t kwsysProcessFork(kwsysProcess* cp,
+                              kwsysProcessCreateInformation* si);
+static void kwsysProcessKill(pid_t process_id);
+#if defined(__VMS)
+static int kwsysProcessSetVMSFeature(const char* name, int value);
+#endif
+static int kwsysProcessesAdd(kwsysProcess* cp);
+static void kwsysProcessesRemove(kwsysProcess* cp);
+#if KWSYSPE_USE_SIGINFO
+static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
+                                        void* ucontext);
+#else
+static void kwsysProcessesSignalHandler(int signum);
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Structure containing data used to implement the child's execution.  */
+struct kwsysProcess_s
+{
+  /* The command lines to execute.  */
+  char*** Commands;
+  volatile int NumberOfCommands;
+
+  /* Descriptors for the read ends of the child's output pipes and
+     the signal pipe. */
+  int PipeReadEnds[KWSYSPE_PIPE_COUNT];
+
+  /* Descriptors for the child's ends of the pipes.
+     Used temporarily during process creation.  */
+  int PipeChildStd[3];
+
+  /* Write descriptor for child termination signal pipe.  */
+  int SignalPipe;
+
+  /* Buffer for pipe data.  */
+  char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
+
+  /* Process IDs returned by the calls to fork.  Everything is volatile
+     because the signal handler accesses them.  You must be very careful
+     when reaping PIDs or modifying this array to avoid race conditions.  */
+  volatile pid_t* volatile ForkPIDs;
+
+  /* Flag for whether the children were terminated by a faild select.  */
+  int SelectError;
+
+  /* The timeout length.  */
+  double Timeout;
+
+  /* The working directory for the process. */
+  char* WorkingDirectory;
+
+  /* Whether to create the child as a detached process.  */
+  int OptionDetach;
+
+  /* Whether the child was created as a detached process.  */
+  int Detached;
+
+  /* Whether to treat command lines as verbatim.  */
+  int Verbatim;
+
+  /* Whether to merge stdout/stderr of the child.  */
+  int MergeOutput;
+
+  /* Whether to create the process in a new process group.  */
+  volatile sig_atomic_t CreateProcessGroup;
+
+  /* Time at which the child started.  Negative for no timeout.  */
+  kwsysProcessTime StartTime;
+
+  /* Time at which the child will timeout.  Negative for no timeout.  */
+  kwsysProcessTime TimeoutTime;
+
+  /* Flag for whether the timeout expired.  */
+  int TimeoutExpired;
+
+  /* The number of pipes left open during execution.  */
+  int PipesLeft;
+
+#if KWSYSPE_USE_SELECT
+  /* File descriptor set for call to select.  */
+  fd_set PipeSet;
+#endif
+
+  /* The number of children still executing.  */
+  int CommandsLeft;
+
+  /* The current status of the child process.  Must be atomic because
+     the signal handler checks this to avoid a race.  */
+  volatile sig_atomic_t State;
+
+  /* The exceptional behavior that terminated the child process, if
+   * any.  */
+  int ExitException;
+
+  /* The exit code of the child process.  */
+  int ExitCode;
+
+  /* The exit value of the child process, if any.  */
+  int ExitValue;
+
+  /* Whether the process was killed.  */
+  volatile sig_atomic_t Killed;
+
+  /* Buffer for error message in case of failure.  */
+  char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1];
+
+  /* Description for the ExitException.  */
+  char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1];
+
+  /* The exit codes of each child process in the pipeline.  */
+  int* CommandExitCodes;
+
+  /* Name of files to which stdin and stdout pipes are attached.  */
+  char* PipeFileSTDIN;
+  char* PipeFileSTDOUT;
+  char* PipeFileSTDERR;
+
+  /* Whether each pipe is shared with the parent process.  */
+  int PipeSharedSTDIN;
+  int PipeSharedSTDOUT;
+  int PipeSharedSTDERR;
+
+  /* Native pipes provided by the user.  */
+  int PipeNativeSTDIN[2];
+  int PipeNativeSTDOUT[2];
+  int PipeNativeSTDERR[2];
+
+  /* The real working directory of this process.  */
+  int RealWorkingDirectoryLength;
+  char* RealWorkingDirectory;
+};
+
+/*--------------------------------------------------------------------------*/
+kwsysProcess* kwsysProcess_New(void)
+{
+  /* Allocate a process control structure.  */
+  kwsysProcess* cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
+  if (!cp) {
+    return 0;
+  }
+  memset(cp, 0, sizeof(kwsysProcess));
+
+  /* Share stdin with the parent process by default.  */
+  cp->PipeSharedSTDIN = 1;
+
+  /* No native pipes by default.  */
+  cp->PipeNativeSTDIN[0] = -1;
+  cp->PipeNativeSTDIN[1] = -1;
+  cp->PipeNativeSTDOUT[0] = -1;
+  cp->PipeNativeSTDOUT[1] = -1;
+  cp->PipeNativeSTDERR[0] = -1;
+  cp->PipeNativeSTDERR[1] = -1;
+
+  /* Set initial status.  */
+  cp->State = kwsysProcess_State_Starting;
+
+  return cp;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Delete(kwsysProcess* cp)
+{
+  /* Make sure we have an instance.  */
+  if (!cp) {
+    return;
+  }
+
+  /* If the process is executing, wait for it to finish.  */
+  if (cp->State == kwsysProcess_State_Executing) {
+    if (cp->Detached) {
+      kwsysProcess_Disown(cp);
+    } else {
+      kwsysProcess_WaitForExit(cp, 0);
+    }
+  }
+
+  /* Free memory.  */
+  kwsysProcess_SetCommand(cp, 0);
+  kwsysProcess_SetWorkingDirectory(cp, 0);
+  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
+  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
+  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
+  if (cp->CommandExitCodes) {
+    free(cp->CommandExitCodes);
+  }
+  free(cp);
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
+{
+  int i;
+  if (!cp) {
+    return 0;
+  }
+  for (i = 0; i < cp->NumberOfCommands; ++i) {
+    char** c = cp->Commands[i];
+    while (*c) {
+      free(*c++);
+    }
+    free(cp->Commands[i]);
+  }
+  cp->NumberOfCommands = 0;
+  if (cp->Commands) {
+    free(cp->Commands);
+    cp->Commands = 0;
+  }
+  if (command) {
+    return kwsysProcess_AddCommand(cp, command);
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
+{
+  int newNumberOfCommands;
+  char*** newCommands;
+
+  /* Make sure we have a command to add.  */
+  if (!cp || !command || !*command) {
+    return 0;
+  }
+
+  /* Allocate a new array for command pointers.  */
+  newNumberOfCommands = cp->NumberOfCommands + 1;
+  if (!(newCommands =
+          (char***)malloc(sizeof(char**) * (size_t)(newNumberOfCommands)))) {
+    /* Out of memory.  */
+    return 0;
+  }
+
+  /* Copy any existing commands into the new array.  */
+  {
+    int i;
+    for (i = 0; i < cp->NumberOfCommands; ++i) {
+      newCommands[i] = cp->Commands[i];
+    }
+  }
+
+  /* Add the new command.  */
+  if (cp->Verbatim) {
+    /* In order to run the given command line verbatim we need to
+       parse it.  */
+    newCommands[cp->NumberOfCommands] =
+      kwsysSystem_Parse_CommandForUnix(*command, 0);
+    if (!newCommands[cp->NumberOfCommands] ||
+        !newCommands[cp->NumberOfCommands][0]) {
+      /* Out of memory or no command parsed.  */
+      free(newCommands);
+      return 0;
+    }
+  } else {
+    /* Copy each argument string individually.  */
+    char const* const* c = command;
+    kwsysProcess_ptrdiff_t n = 0;
+    kwsysProcess_ptrdiff_t i = 0;
+    while (*c++)
+      ;
+    n = c - command - 1;
+    newCommands[cp->NumberOfCommands] =
+      (char**)malloc((size_t)(n + 1) * sizeof(char*));
+    if (!newCommands[cp->NumberOfCommands]) {
+      /* Out of memory.  */
+      free(newCommands);
+      return 0;
+    }
+    for (i = 0; i < n; ++i) {
+      assert(command[i]); /* Quiet Clang scan-build. */
+      newCommands[cp->NumberOfCommands][i] = strdup(command[i]);
+      if (!newCommands[cp->NumberOfCommands][i]) {
+        break;
+      }
+    }
+    if (i < n) {
+      /* Out of memory.  */
+      for (; i > 0; --i) {
+        free(newCommands[cp->NumberOfCommands][i - 1]);
+      }
+      free(newCommands);
+      return 0;
+    }
+    newCommands[cp->NumberOfCommands][n] = 0;
+  }
+
+  /* Successfully allocated new command array.  Free the old array. */
+  free(cp->Commands);
+  cp->Commands = newCommands;
+  cp->NumberOfCommands = newNumberOfCommands;
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
+{
+  if (!cp) {
+    return;
+  }
+  cp->Timeout = timeout;
+  if (cp->Timeout < 0) {
+    cp->Timeout = 0;
+  }
+  // Force recomputation of TimeoutTime.
+  cp->TimeoutTime.tv_sec = -1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
+{
+  if (!cp) {
+    return 0;
+  }
+  if (cp->WorkingDirectory == dir) {
+    return 1;
+  }
+  if (cp->WorkingDirectory && dir && strcmp(cp->WorkingDirectory, dir) == 0) {
+    return 1;
+  }
+  if (cp->WorkingDirectory) {
+    free(cp->WorkingDirectory);
+    cp->WorkingDirectory = 0;
+  }
+  if (dir) {
+    cp->WorkingDirectory = (char*)malloc(strlen(dir) + 1);
+    if (!cp->WorkingDirectory) {
+      return 0;
+    }
+    strcpy(cp->WorkingDirectory, dir);
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetPipeFile(kwsysProcess* cp, int prPipe, const char* file)
+{
+  char** pfile;
+  if (!cp) {
+    return 0;
+  }
+  switch (prPipe) {
+    case kwsysProcess_Pipe_STDIN:
+      pfile = &cp->PipeFileSTDIN;
+      break;
+    case kwsysProcess_Pipe_STDOUT:
+      pfile = &cp->PipeFileSTDOUT;
+      break;
+    case kwsysProcess_Pipe_STDERR:
+      pfile = &cp->PipeFileSTDERR;
+      break;
+    default:
+      return 0;
+  }
+  if (*pfile) {
+    free(*pfile);
+    *pfile = 0;
+  }
+  if (file) {
+    *pfile = (char*)malloc(strlen(file) + 1);
+    if (!*pfile) {
+      return 0;
+    }
+    strcpy(*pfile, file);
+  }
+
+  /* If we are redirecting the pipe, do not share it or use a native
+     pipe.  */
+  if (*pfile) {
+    kwsysProcess_SetPipeNative(cp, prPipe, 0);
+    kwsysProcess_SetPipeShared(cp, prPipe, 0);
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeShared(kwsysProcess* cp, int prPipe, int shared)
+{
+  if (!cp) {
+    return;
+  }
+
+  switch (prPipe) {
+    case kwsysProcess_Pipe_STDIN:
+      cp->PipeSharedSTDIN = shared ? 1 : 0;
+      break;
+    case kwsysProcess_Pipe_STDOUT:
+      cp->PipeSharedSTDOUT = shared ? 1 : 0;
+      break;
+    case kwsysProcess_Pipe_STDERR:
+      cp->PipeSharedSTDERR = shared ? 1 : 0;
+      break;
+    default:
+      return;
+  }
+
+  /* If we are sharing the pipe, do not redirect it to a file or use a
+     native pipe.  */
+  if (shared) {
+    kwsysProcess_SetPipeFile(cp, prPipe, 0);
+    kwsysProcess_SetPipeNative(cp, prPipe, 0);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, int p[2])
+{
+  int* pPipeNative = 0;
+
+  if (!cp) {
+    return;
+  }
+
+  switch (prPipe) {
+    case kwsysProcess_Pipe_STDIN:
+      pPipeNative = cp->PipeNativeSTDIN;
+      break;
+    case kwsysProcess_Pipe_STDOUT:
+      pPipeNative = cp->PipeNativeSTDOUT;
+      break;
+    case kwsysProcess_Pipe_STDERR:
+      pPipeNative = cp->PipeNativeSTDERR;
+      break;
+    default:
+      return;
+  }
+
+  /* Copy the native pipe descriptors provided.  */
+  if (p) {
+    pPipeNative[0] = p[0];
+    pPipeNative[1] = p[1];
+  } else {
+    pPipeNative[0] = -1;
+    pPipeNative[1] = -1;
+  }
+
+  /* If we are using a native pipe, do not share it or redirect it to
+     a file.  */
+  if (p) {
+    kwsysProcess_SetPipeFile(cp, prPipe, 0);
+    kwsysProcess_SetPipeShared(cp, prPipe, 0);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
+{
+  if (!cp) {
+    return 0;
+  }
+
+  switch (optionId) {
+    case kwsysProcess_Option_Detach:
+      return cp->OptionDetach;
+    case kwsysProcess_Option_MergeOutput:
+      return cp->MergeOutput;
+    case kwsysProcess_Option_Verbatim:
+      return cp->Verbatim;
+    case kwsysProcess_Option_CreateProcessGroup:
+      return cp->CreateProcessGroup;
+    default:
+      return 0;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
+{
+  if (!cp) {
+    return;
+  }
+
+  switch (optionId) {
+    case kwsysProcess_Option_Detach:
+      cp->OptionDetach = value;
+      break;
+    case kwsysProcess_Option_MergeOutput:
+      cp->MergeOutput = value;
+      break;
+    case kwsysProcess_Option_Verbatim:
+      cp->Verbatim = value;
+      break;
+    case kwsysProcess_Option_CreateProcessGroup:
+      cp->CreateProcessGroup = value;
+      break;
+    default:
+      break;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetState(kwsysProcess* cp)
+{
+  return cp ? cp->State : kwsysProcess_State_Error;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitException(kwsysProcess* cp)
+{
+  return cp ? cp->ExitException : kwsysProcess_Exception_Other;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitCode(kwsysProcess* cp)
+{
+  return cp ? cp->ExitCode : 0;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitValue(kwsysProcess* cp)
+{
+  return cp ? cp->ExitValue : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
+{
+  if (!cp) {
+    return "Process management structure could not be allocated";
+  } else if (cp->State == kwsysProcess_State_Error) {
+    return cp->ErrorMessage;
+  }
+  return "Success";
+}
+
+/*--------------------------------------------------------------------------*/
+const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
+{
+  if (!cp) {
+    return "GetExceptionString called with NULL process management structure";
+  } else if (cp->State == kwsysProcess_State_Exception) {
+    return cp->ExitExceptionString;
+  }
+  return "No exception";
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Execute(kwsysProcess* cp)
+{
+  int i;
+
+  /* Do not execute a second copy simultaneously.  */
+  if (!cp || cp->State == kwsysProcess_State_Executing) {
+    return;
+  }
+
+  /* Make sure we have something to run.  */
+  if (cp->NumberOfCommands < 1) {
+    strcpy(cp->ErrorMessage, "No command");
+    cp->State = kwsysProcess_State_Error;
+    return;
+  }
+
+  /* Initialize the control structure for a new process.  */
+  if (!kwsysProcessInitialize(cp)) {
+    strcpy(cp->ErrorMessage, "Out of memory");
+    cp->State = kwsysProcess_State_Error;
+    return;
+  }
+
+#if defined(__VMS)
+  /* Make sure pipes behave like streams on VMS.  */
+  if (!kwsysProcessSetVMSFeature("DECC$STREAM_PIPE", 1)) {
+    kwsysProcessCleanup(cp, 1);
+    return;
+  }
+#endif
+
+  /* Save the real working directory of this process and change to
+     the working directory for the child processes.  This is needed
+     to make pipe file paths evaluate correctly.  */
+  if (cp->WorkingDirectory) {
+    int r;
+    if (!getcwd(cp->RealWorkingDirectory,
+                (size_t)(cp->RealWorkingDirectoryLength))) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+
+    /* Some platforms specify that the chdir call may be
+       interrupted.  Repeat the call until it finishes.  */
+    while (((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR))
+      ;
+    if (r < 0) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  }
+
+  /* If not running a detached child, add this object to the global
+     set of process objects that wish to be notified when a child
+     exits.  */
+  if (!cp->OptionDetach) {
+    if (!kwsysProcessesAdd(cp)) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  }
+
+  /* Setup the stdin pipe for the first process.  */
+  if (cp->PipeFileSTDIN) {
+    /* Open a file for the child's stdin to read.  */
+    cp->PipeChildStd[0] = open(cp->PipeFileSTDIN, O_RDONLY);
+    if (cp->PipeChildStd[0] < 0) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+
+    /* Set close-on-exec flag on the pipe's end.  */
+    if (fcntl(cp->PipeChildStd[0], F_SETFD, FD_CLOEXEC) < 0) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  } else if (cp->PipeSharedSTDIN) {
+    cp->PipeChildStd[0] = 0;
+  } else if (cp->PipeNativeSTDIN[0] >= 0) {
+    cp->PipeChildStd[0] = cp->PipeNativeSTDIN[0];
+
+    /* Set close-on-exec flag on the pipe's ends.  The read end will
+       be dup2-ed into the stdin descriptor after the fork but before
+       the exec.  */
+    if ((fcntl(cp->PipeNativeSTDIN[0], F_SETFD, FD_CLOEXEC) < 0) ||
+        (fcntl(cp->PipeNativeSTDIN[1], F_SETFD, FD_CLOEXEC) < 0)) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  } else {
+    cp->PipeChildStd[0] = -1;
+  }
+
+  /* Create the output pipe for the last process.
+     We always create this so the pipe can be passed to select even if
+     it will report closed immediately.  */
+  {
+    /* Create the pipe.  */
+    int p[2];
+    if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+
+    /* Store the pipe.  */
+    cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = p[0];
+    cp->PipeChildStd[1] = p[1];
+
+    /* Set close-on-exec flag on the pipe's ends.  */
+    if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+        (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+
+    /* Set to non-blocking in case select lies, or for the polling
+       implementation.  */
+    if (!kwsysProcessSetNonBlocking(p[0])) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  }
+
+  if (cp->PipeFileSTDOUT) {
+    /* Use a file for stdout.  */
+    if (!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
+                                         cp->PipeFileSTDOUT)) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  } else if (cp->PipeSharedSTDOUT) {
+    /* Use the parent stdout.  */
+    kwsysProcessCleanupDescriptor(&cp->PipeChildStd[1]);
+    cp->PipeChildStd[1] = 1;
+  } else if (cp->PipeNativeSTDOUT[1] >= 0) {
+    /* Use the given descriptor for stdout.  */
+    if (!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[1],
+                                           cp->PipeNativeSTDOUT)) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  }
+
+  /* Create stderr pipe to be shared by all processes in the pipeline.
+     We always create this so the pipe can be passed to select even if
+     it will report closed immediately.  */
+  {
+    /* Create the pipe.  */
+    int p[2];
+    if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+
+    /* Store the pipe.  */
+    cp->PipeReadEnds[KWSYSPE_PIPE_STDERR] = p[0];
+    cp->PipeChildStd[2] = p[1];
+
+    /* Set close-on-exec flag on the pipe's ends.  */
+    if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+        (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+
+    /* Set to non-blocking in case select lies, or for the polling
+       implementation.  */
+    if (!kwsysProcessSetNonBlocking(p[0])) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  }
+
+  if (cp->PipeFileSTDERR) {
+    /* Use a file for stderr.  */
+    if (!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
+                                         cp->PipeFileSTDERR)) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  } else if (cp->PipeSharedSTDERR) {
+    /* Use the parent stderr.  */
+    kwsysProcessCleanupDescriptor(&cp->PipeChildStd[2]);
+    cp->PipeChildStd[2] = 2;
+  } else if (cp->PipeNativeSTDERR[1] >= 0) {
+    /* Use the given handle for stderr.  */
+    if (!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[2],
+                                           cp->PipeNativeSTDERR)) {
+      kwsysProcessCleanup(cp, 1);
+      return;
+    }
+  }
+
+  /* The timeout period starts now.  */
+  cp->StartTime = kwsysProcessTimeGetCurrent();
+  cp->TimeoutTime.tv_sec = -1;
+  cp->TimeoutTime.tv_usec = -1;
+
+  /* Create the pipeline of processes.  */
+  {
+    kwsysProcessCreateInformation si = { -1, -1, -1, { -1, -1 } };
+    int nextStdIn = cp->PipeChildStd[0];
+    for (i = 0; i < cp->NumberOfCommands; ++i) {
+      /* Setup the process's pipes.  */
+      si.StdIn = nextStdIn;
+      if (i == cp->NumberOfCommands - 1) {
+        nextStdIn = -1;
+        si.StdOut = cp->PipeChildStd[1];
+      } else {
+        /* Create a pipe to sit between the children.  */
+        int p[2] = { -1, -1 };
+        if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) {
+          if (nextStdIn != cp->PipeChildStd[0]) {
+            kwsysProcessCleanupDescriptor(&nextStdIn);
+          }
+          kwsysProcessCleanup(cp, 1);
+          return;
+        }
+
+        /* Set close-on-exec flag on the pipe's ends.  */
+        if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+            (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) {
+          close(p[0]);
+          close(p[1]);
+          if (nextStdIn != cp->PipeChildStd[0]) {
+            kwsysProcessCleanupDescriptor(&nextStdIn);
+          }
+          kwsysProcessCleanup(cp, 1);
+          return;
+        }
+        nextStdIn = p[0];
+        si.StdOut = p[1];
+      }
+      si.StdErr = cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2];
+
+      {
+        int res = kwsysProcessCreate(cp, i, &si);
+
+        /* Close our copies of pipes used between children.  */
+        if (si.StdIn != cp->PipeChildStd[0]) {
+          kwsysProcessCleanupDescriptor(&si.StdIn);
+        }
+        if (si.StdOut != cp->PipeChildStd[1]) {
+          kwsysProcessCleanupDescriptor(&si.StdOut);
+        }
+        if (si.StdErr != cp->PipeChildStd[2] && !cp->MergeOutput) {
+          kwsysProcessCleanupDescriptor(&si.StdErr);
+        }
+
+        if (!res) {
+          kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]);
+          kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]);
+          if (nextStdIn != cp->PipeChildStd[0]) {
+            kwsysProcessCleanupDescriptor(&nextStdIn);
+          }
+          kwsysProcessCleanup(cp, 1);
+          return;
+        }
+      }
+    }
+  }
+
+  /* The parent process does not need the child's pipe ends.  */
+  for (i = 0; i < 3; ++i) {
+    kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]);
+  }
+
+  /* Restore the working directory. */
+  if (cp->RealWorkingDirectory) {
+    /* Some platforms specify that the chdir call may be
+       interrupted.  Repeat the call until it finishes.  */
+    while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR))
+      ;
+    free(cp->RealWorkingDirectory);
+    cp->RealWorkingDirectory = 0;
+  }
+
+  /* All the pipes are now open.  */
+  cp->PipesLeft = KWSYSPE_PIPE_COUNT;
+
+  /* The process has now started.  */
+  cp->State = kwsysProcess_State_Executing;
+  cp->Detached = cp->OptionDetach;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
+{
+  /* Make sure a detached child process is running.  */
+  if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
+      cp->TimeoutExpired || cp->Killed) {
+    return;
+  }
+
+  /* Close all the pipes safely.  */
+  kwsysProcessClosePipes(cp);
+
+  /* We will not wait for exit, so cleanup now.  */
+  kwsysProcessCleanup(cp, 0);
+
+  /* The process has been disowned.  */
+  cp->State = kwsysProcess_State_Disowned;
+}
+
+/*--------------------------------------------------------------------------*/
+typedef struct kwsysProcessWaitData_s
+{
+  int Expired;
+  int PipeId;
+  int User;
+  double* UserTimeout;
+  kwsysProcessTime TimeoutTime;
+} kwsysProcessWaitData;
+static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
+                                   kwsysProcessWaitData* wd);
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
+                             double* userTimeout)
+{
+  kwsysProcessTime userStartTime = { 0, 0 };
+  kwsysProcessWaitData wd = { 0, kwsysProcess_Pipe_None, 0, 0, { 0, 0 } };
+  wd.UserTimeout = userTimeout;
+  /* Make sure we are executing a process.  */
+  if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
+      cp->TimeoutExpired) {
+    return kwsysProcess_Pipe_None;
+  }
+
+  /* Record the time at which user timeout period starts.  */
+  if (userTimeout) {
+    userStartTime = kwsysProcessTimeGetCurrent();
+  }
+
+  /* Calculate the time at which a timeout will expire, and whether it
+     is the user or process timeout.  */
+  wd.User = kwsysProcessGetTimeoutTime(cp, userTimeout, &wd.TimeoutTime);
+
+  /* Data can only be available when pipes are open.  If the process
+     is not running, cp->PipesLeft will be 0.  */
+  while (cp->PipesLeft > 0 &&
+         !kwsysProcessWaitForPipe(cp, data, length, &wd)) {
+  }
+
+  /* Update the user timeout.  */
+  if (userTimeout) {
+    kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
+    kwsysProcessTime difference =
+      kwsysProcessTimeSubtract(userEndTime, userStartTime);
+    double d = kwsysProcessTimeToDouble(difference);
+    *userTimeout -= d;
+    if (*userTimeout < 0) {
+      *userTimeout = 0;
+    }
+  }
+
+  /* Check what happened.  */
+  if (wd.PipeId) {
+    /* Data are ready on a pipe.  */
+    return wd.PipeId;
+  } else if (wd.Expired) {
+    /* A timeout has expired.  */
+    if (wd.User) {
+      /* The user timeout has expired.  It has no time left.  */
+      return kwsysProcess_Pipe_Timeout;
+    } else {
+      /* The process timeout has expired.  Kill the children now.  */
+      kwsysProcess_Kill(cp);
+      cp->Killed = 0;
+      cp->TimeoutExpired = 1;
+      return kwsysProcess_Pipe_None;
+    }
+  } else {
+    /* No pipes are left open.  */
+    return kwsysProcess_Pipe_None;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
+                                   kwsysProcessWaitData* wd)
+{
+  int i;
+  kwsysProcessTimeNative timeoutLength;
+
+#if KWSYSPE_USE_SELECT
+  int numReady = 0;
+  int max = -1;
+  kwsysProcessTimeNative* timeout = 0;
+
+  /* Check for any open pipes with data reported ready by the last
+     call to select.  According to "man select_tut" we must deal
+     with all descriptors reported by a call to select before
+     passing them to another select call.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    if (cp->PipeReadEnds[i] >= 0 &&
+        FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet)) {
+      kwsysProcess_ssize_t n;
+
+      /* We are handling this pipe now.  Remove it from the set.  */
+      FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet);
+
+      /* The pipe is ready to read without blocking.  Keep trying to
+         read until the operation is not interrupted.  */
+      while (((n = read(cp->PipeReadEnds[i], cp->PipeBuffer,
+                        KWSYSPE_PIPE_BUFFER_SIZE)) < 0) &&
+             (errno == EINTR))
+        ;
+      if (n > 0) {
+        /* We have data on this pipe.  */
+        if (i == KWSYSPE_PIPE_SIGNAL) {
+          /* A child process has terminated.  */
+          kwsysProcessDestroy(cp);
+        } else if (data && length) {
+          /* Report this data.  */
+          *data = cp->PipeBuffer;
+          *length = (int)(n);
+          switch (i) {
+            case KWSYSPE_PIPE_STDOUT:
+              wd->PipeId = kwsysProcess_Pipe_STDOUT;
+              break;
+            case KWSYSPE_PIPE_STDERR:
+              wd->PipeId = kwsysProcess_Pipe_STDERR;
+              break;
+          };
+          return 1;
+        }
+      } else if (n < 0 && errno == EAGAIN) {
+        /* No data are really ready.  The select call lied.  See the
+           "man select" page on Linux for cases when this occurs.  */
+      } else {
+        /* We are done reading from this pipe.  */
+        kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+        --cp->PipesLeft;
+      }
+    }
+  }
+
+  /* If we have data, break early.  */
+  if (wd->PipeId) {
+    return 1;
+  }
+
+  /* Make sure the set is empty (it should always be empty here
+     anyway).  */
+  FD_ZERO(&cp->PipeSet);
+
+  /* Setup a timeout if required.  */
+  if (wd->TimeoutTime.tv_sec < 0) {
+    timeout = 0;
+  } else {
+    timeout = &timeoutLength;
+  }
+  if (kwsysProcessGetTimeoutLeft(
+        &wd->TimeoutTime, wd->User ? wd->UserTimeout : 0, &timeoutLength, 0)) {
+    /* Timeout has already expired.  */
+    wd->Expired = 1;
+    return 1;
+  }
+
+  /* Add the pipe reading ends that are still open.  */
+  max = -1;
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    if (cp->PipeReadEnds[i] >= 0) {
+      FD_SET(cp->PipeReadEnds[i], &cp->PipeSet);
+      if (cp->PipeReadEnds[i] > max) {
+        max = cp->PipeReadEnds[i];
+      }
+    }
+  }
+
+  /* Make sure we have a non-empty set.  */
+  if (max < 0) {
+    /* All pipes have closed.  Child has terminated.  */
+    return 1;
+  }
+
+  /* Run select to block until data are available.  Repeat call
+     until it is not interrupted.  */
+  while (((numReady = select(max + 1, &cp->PipeSet, 0, 0, timeout)) < 0) &&
+         (errno == EINTR))
+    ;
+
+  /* Check result of select.  */
+  if (numReady == 0) {
+    /* Select's timeout expired.  */
+    wd->Expired = 1;
+    return 1;
+  } else if (numReady < 0) {
+    /* Select returned an error.  Leave the error description in the
+       pipe buffer.  */
+    strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+
+    /* Kill the children now.  */
+    kwsysProcess_Kill(cp);
+    cp->Killed = 0;
+    cp->SelectError = 1;
+  }
+
+  return 0;
+#else
+  /* Poll pipes for data since we do not have select.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    if (cp->PipeReadEnds[i] >= 0) {
+      const int fd = cp->PipeReadEnds[i];
+      int n = read(fd, cp->PipeBuffer, KWSYSPE_PIPE_BUFFER_SIZE);
+      if (n > 0) {
+        /* We have data on this pipe.  */
+        if (i == KWSYSPE_PIPE_SIGNAL) {
+          /* A child process has terminated.  */
+          kwsysProcessDestroy(cp);
+        } else if (data && length) {
+          /* Report this data.  */
+          *data = cp->PipeBuffer;
+          *length = n;
+          switch (i) {
+            case KWSYSPE_PIPE_STDOUT:
+              wd->PipeId = kwsysProcess_Pipe_STDOUT;
+              break;
+            case KWSYSPE_PIPE_STDERR:
+              wd->PipeId = kwsysProcess_Pipe_STDERR;
+              break;
+          };
+        }
+        return 1;
+      } else if (n == 0) /* EOF */
+      {
+/* We are done reading from this pipe.  */
+#if defined(__VMS)
+        if (!cp->CommandsLeft)
+#endif
+        {
+          kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+          --cp->PipesLeft;
+        }
+      } else if (n < 0) /* error */
+      {
+#if defined(__VMS)
+        if (!cp->CommandsLeft) {
+          kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+          --cp->PipesLeft;
+        } else
+#endif
+          if ((errno != EINTR) && (errno != EAGAIN)) {
+          strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+          /* Kill the children now.  */
+          kwsysProcess_Kill(cp);
+          cp->Killed = 0;
+          cp->SelectError = 1;
+          return 1;
+        }
+      }
+    }
+  }
+
+  /* If we have data, break early.  */
+  if (wd->PipeId) {
+    return 1;
+  }
+
+  if (kwsysProcessGetTimeoutLeft(
+        &wd->TimeoutTime, wd->User ? wd->UserTimeout : 0, &timeoutLength, 1)) {
+    /* Timeout has already expired.  */
+    wd->Expired = 1;
+    return 1;
+  }
+
+  /* Sleep a little, try again. */
+  {
+    unsigned int msec =
+      ((timeoutLength.tv_sec * 1000) + (timeoutLength.tv_usec / 1000));
+    if (msec > 100000) {
+      msec = 100000; /* do not sleep more than 100 milliseconds at a time */
+    }
+    kwsysProcess_usleep(msec);
+  }
+  return 0;
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
+{
+  int status = 0;
+  int prPipe = 0;
+
+  /* Make sure we are executing a process.  */
+  if (!cp || cp->State != kwsysProcess_State_Executing) {
+    return 1;
+  }
+
+  /* Wait for all the pipes to close.  Ignore all data.  */
+  while ((prPipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) {
+    if (prPipe == kwsysProcess_Pipe_Timeout) {
+      return 0;
+    }
+  }
+
+  /* Check if there was an error in one of the waitpid calls.  */
+  if (cp->State == kwsysProcess_State_Error) {
+    /* The error message is already in its buffer.  Tell
+       kwsysProcessCleanup to not create it.  */
+    kwsysProcessCleanup(cp, 0);
+    return 1;
+  }
+
+  /* Check whether the child reported an error invoking the process.  */
+  if (cp->SelectError) {
+    /* The error message is already in its buffer.  Tell
+       kwsysProcessCleanup to not create it.  */
+    kwsysProcessCleanup(cp, 0);
+    cp->State = kwsysProcess_State_Error;
+    return 1;
+  }
+
+  /* Use the status of the last process in the pipeline.  */
+  status = cp->CommandExitCodes[cp->NumberOfCommands - 1];
+
+  /* Determine the outcome.  */
+  if (cp->Killed) {
+    /* We killed the child.  */
+    cp->State = kwsysProcess_State_Killed;
+  } else if (cp->TimeoutExpired) {
+    /* The timeout expired.  */
+    cp->State = kwsysProcess_State_Expired;
+  } else if (WIFEXITED(status)) {
+    /* The child exited normally.  */
+    cp->State = kwsysProcess_State_Exited;
+    cp->ExitException = kwsysProcess_Exception_None;
+    cp->ExitCode = status;
+    cp->ExitValue = (int)WEXITSTATUS(status);
+  } else if (WIFSIGNALED(status)) {
+    /* The child received an unhandled signal.  */
+    cp->State = kwsysProcess_State_Exception;
+    cp->ExitCode = status;
+    kwsysProcessSetExitException(cp, (int)WTERMSIG(status));
+  } else {
+    /* Error getting the child return code.  */
+    strcpy(cp->ErrorMessage, "Error getting child return code.");
+    cp->State = kwsysProcess_State_Error;
+  }
+
+  /* Normal cleanup.  */
+  kwsysProcessCleanup(cp, 0);
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Interrupt(kwsysProcess* cp)
+{
+  int i;
+  /* Make sure we are executing a process.  */
+  if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+      cp->Killed) {
+    return;
+  }
+
+  /* Interrupt the children.  */
+  if (cp->CreateProcessGroup) {
+    if (cp->ForkPIDs) {
+      for (i = 0; i < cp->NumberOfCommands; ++i) {
+        /* Make sure the PID is still valid. */
+        if (cp->ForkPIDs[i]) {
+          /* The user created a process group for this process.  The group ID
+             is the process ID for the original process in the group.  */
+          kill(-cp->ForkPIDs[i], SIGINT);
+        }
+      }
+    }
+  } else {
+    /* No process group was created.  Kill our own process group.
+       NOTE:  While one could argue that we could call kill(cp->ForkPIDs[i],
+       SIGINT) as a way to still interrupt the process even though it's not in
+       a special group, this is not an option on Windows.  Therefore, we kill
+       the current process group for consistency with Windows.  */
+    kill(0, SIGINT);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Kill(kwsysProcess* cp)
+{
+  int i;
+
+  /* Make sure we are executing a process.  */
+  if (!cp || cp->State != kwsysProcess_State_Executing) {
+    return;
+  }
+
+  /* First close the child exit report pipe write end to avoid causing a
+     SIGPIPE when the child terminates and our signal handler tries to
+     report it after we have already closed the read end.  */
+  kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+
+#if !defined(__APPLE__)
+  /* Close all the pipe read ends.  Do this before killing the
+     children because Cygwin has problems killing processes that are
+     blocking to wait for writing to their output pipes.  */
+  kwsysProcessClosePipes(cp);
+#endif
+
+  /* Kill the children.  */
+  cp->Killed = 1;
+  for (i = 0; i < cp->NumberOfCommands; ++i) {
+    int status;
+    if (cp->ForkPIDs[i]) {
+      /* Kill the child.  */
+      kwsysProcessKill(cp->ForkPIDs[i]);
+
+      /* Reap the child.  Keep trying until the call is not
+         interrupted.  */
+      while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR))
+        ;
+    }
+  }
+
+#if defined(__APPLE__)
+  /* Close all the pipe read ends.  Do this after killing the
+     children because OS X has problems closing pipe read ends whose
+     pipes are full and still have an open write end.  */
+  kwsysProcessClosePipes(cp);
+#endif
+
+  cp->CommandsLeft = 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Call the free() function with a pointer to volatile without causing
+   compiler warnings.  */
+static void kwsysProcessVolatileFree(volatile void* p)
+{
+/* clang has made it impossible to free memory that points to volatile
+   without first using special pragmas to disable a warning...  */
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wcast-qual"
+#endif
+  free((void*)p); /* The cast will silence most compilers, but not clang.  */
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+#pragma clang diagnostic pop
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* Initialize a process control structure for kwsysProcess_Execute.  */
+static int kwsysProcessInitialize(kwsysProcess* cp)
+{
+  int i;
+  volatile pid_t* oldForkPIDs;
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    cp->PipeReadEnds[i] = -1;
+  }
+  for (i = 0; i < 3; ++i) {
+    cp->PipeChildStd[i] = -1;
+  }
+  cp->SignalPipe = -1;
+  cp->SelectError = 0;
+  cp->StartTime.tv_sec = -1;
+  cp->StartTime.tv_usec = -1;
+  cp->TimeoutTime.tv_sec = -1;
+  cp->TimeoutTime.tv_usec = -1;
+  cp->TimeoutExpired = 0;
+  cp->PipesLeft = 0;
+  cp->CommandsLeft = 0;
+#if KWSYSPE_USE_SELECT
+  FD_ZERO(&cp->PipeSet);
+#endif
+  cp->State = kwsysProcess_State_Starting;
+  cp->Killed = 0;
+  cp->ExitException = kwsysProcess_Exception_None;
+  cp->ExitCode = 1;
+  cp->ExitValue = 1;
+  cp->ErrorMessage[0] = 0;
+  strcpy(cp->ExitExceptionString, "No exception");
+
+  oldForkPIDs = cp->ForkPIDs;
+  cp->ForkPIDs = (volatile pid_t*)malloc(sizeof(volatile pid_t) *
+                                         (size_t)(cp->NumberOfCommands));
+  if (oldForkPIDs) {
+    kwsysProcessVolatileFree(oldForkPIDs);
+  }
+  if (!cp->ForkPIDs) {
+    return 0;
+  }
+  for (i = 0; i < cp->NumberOfCommands; ++i) {
+    cp->ForkPIDs[i] = 0; /* can't use memset due to volatile */
+  }
+
+  if (cp->CommandExitCodes) {
+    free(cp->CommandExitCodes);
+  }
+  cp->CommandExitCodes =
+    (int*)malloc(sizeof(int) * (size_t)(cp->NumberOfCommands));
+  if (!cp->CommandExitCodes) {
+    return 0;
+  }
+  memset(cp->CommandExitCodes, 0,
+         sizeof(int) * (size_t)(cp->NumberOfCommands));
+
+  /* Allocate memory to save the real working directory.  */
+  if (cp->WorkingDirectory) {
+#if defined(MAXPATHLEN)
+    cp->RealWorkingDirectoryLength = MAXPATHLEN;
+#elif defined(PATH_MAX)
+    cp->RealWorkingDirectoryLength = PATH_MAX;
+#else
+    cp->RealWorkingDirectoryLength = 4096;
+#endif
+    cp->RealWorkingDirectory =
+      (char*)malloc((size_t)(cp->RealWorkingDirectoryLength));
+    if (!cp->RealWorkingDirectory) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Free all resources used by the given kwsysProcess instance that were
+   allocated by kwsysProcess_Execute.  */
+static void kwsysProcessCleanup(kwsysProcess* cp, int error)
+{
+  int i;
+
+  if (error) {
+    /* We are cleaning up due to an error.  Report the error message
+       if one has not been provided already.  */
+    if (cp->ErrorMessage[0] == 0) {
+      strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+    }
+
+    /* Set the error state.  */
+    cp->State = kwsysProcess_State_Error;
+
+    /* Kill any children already started.  */
+    if (cp->ForkPIDs) {
+      int status;
+      for (i = 0; i < cp->NumberOfCommands; ++i) {
+        if (cp->ForkPIDs[i]) {
+          /* Kill the child.  */
+          kwsysProcessKill(cp->ForkPIDs[i]);
+
+          /* Reap the child.  Keep trying until the call is not
+             interrupted.  */
+          while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) &&
+                 (errno == EINTR))
+            ;
+        }
+      }
+    }
+
+    /* Restore the working directory.  */
+    if (cp->RealWorkingDirectory) {
+      while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR))
+        ;
+    }
+  }
+
+  /* If not creating a detached child, remove this object from the
+     global set of process objects that wish to be notified when a
+     child exits.  */
+  if (!cp->OptionDetach) {
+    kwsysProcessesRemove(cp);
+  }
+
+  /* Free memory.  */
+  if (cp->ForkPIDs) {
+    kwsysProcessVolatileFree(cp->ForkPIDs);
+    cp->ForkPIDs = 0;
+  }
+  if (cp->RealWorkingDirectory) {
+    free(cp->RealWorkingDirectory);
+    cp->RealWorkingDirectory = 0;
+  }
+
+  /* Close pipe handles.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+  }
+  for (i = 0; i < 3; ++i) {
+    kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Close the given file descriptor if it is open.  Reset its value to -1.  */
+static void kwsysProcessCleanupDescriptor(int* pfd)
+{
+  if (pfd && *pfd > 2) {
+    /* Keep trying to close until it is not interrupted by a
+     * signal.  */
+    while ((close(*pfd) < 0) && (errno == EINTR))
+      ;
+    *pfd = -1;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessClosePipes(kwsysProcess* cp)
+{
+  int i;
+
+  /* Close any pipes that are still open.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    if (cp->PipeReadEnds[i] >= 0) {
+#if KWSYSPE_USE_SELECT
+      /* If the pipe was reported by the last call to select, we must
+         read from it.  This is needed to satisfy the suggestions from
+         "man select_tut" and is not needed for the polling
+         implementation.  Ignore the data.  */
+      if (FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet)) {
+        /* We are handling this pipe now.  Remove it from the set.  */
+        FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet);
+
+        /* The pipe is ready to read without blocking.  Keep trying to
+           read until the operation is not interrupted.  */
+        while ((read(cp->PipeReadEnds[i], cp->PipeBuffer,
+                     KWSYSPE_PIPE_BUFFER_SIZE) < 0) &&
+               (errno == EINTR))
+          ;
+      }
+#endif
+
+      /* We are done reading from this pipe.  */
+      kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
+      --cp->PipesLeft;
+    }
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessSetNonBlocking(int fd)
+{
+  int flags = fcntl(fd, F_GETFL);
+  if (flags >= 0) {
+    flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+  }
+  return flags >= 0;
+}
+
+/*--------------------------------------------------------------------------*/
+#if defined(__VMS)
+int decc$set_child_standard_streams(int fd1, int fd2, int fd3);
+#endif
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
+                              kwsysProcessCreateInformation* si)
+{
+  sigset_t mask, old_mask;
+  int pgidPipe[2];
+  char tmp;
+  ssize_t readRes;
+
+  /* Create the error reporting pipe.  */
+  if (pipe(si->ErrorPipe) < 0) {
+    return 0;
+  }
+
+  /* Create a pipe for detecting that the child process has created a process
+     group and session.  */
+  if (pipe(pgidPipe) < 0) {
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+    return 0;
+  }
+
+  /* Set close-on-exec flag on the pipe's write end.  */
+  if (fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0 ||
+      fcntl(pgidPipe[1], F_SETFD, FD_CLOEXEC) < 0) {
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+    kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+    kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+    return 0;
+  }
+
+  /* Block SIGINT / SIGTERM while we start.  The purpose is so that our signal
+     handler doesn't get called from the child process after the fork and
+     before the exec, and subsequently start kill()'ing PIDs from ForkPIDs. */
+  sigemptyset(&mask);
+  sigaddset(&mask, SIGINT);
+  sigaddset(&mask, SIGTERM);
+  if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+    kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+    kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+    return 0;
+  }
+
+/* Fork off a child process.  */
+#if defined(__VMS)
+  /* VMS needs vfork and execvp to be in the same function because
+     they use setjmp/longjmp to run the child startup code in the
+     parent!  TODO: OptionDetach.  Also
+     TODO:  CreateProcessGroup.  */
+  cp->ForkPIDs[prIndex] = vfork();
+#else
+  cp->ForkPIDs[prIndex] = kwsysProcessFork(cp, si);
+#endif
+  if (cp->ForkPIDs[prIndex] < 0) {
+    sigprocmask(SIG_SETMASK, &old_mask, 0);
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+    kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+    kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+    return 0;
+  }
+
+  if (cp->ForkPIDs[prIndex] == 0) {
+#if defined(__VMS)
+    /* Specify standard pipes for child process.  */
+    decc$set_child_standard_streams(si->StdIn, si->StdOut, si->StdErr);
+#else
+    /* Close the read end of the error reporting / process group
+       setup pipe.  */
+    close(si->ErrorPipe[0]);
+    close(pgidPipe[0]);
+
+    /* Setup the stdin, stdout, and stderr pipes.  */
+    if (si->StdIn > 0) {
+      dup2(si->StdIn, 0);
+    } else if (si->StdIn < 0) {
+      close(0);
+    }
+    if (si->StdOut != 1) {
+      dup2(si->StdOut, 1);
+    }
+    if (si->StdErr != 2) {
+      dup2(si->StdErr, 2);
+    }
+
+    /* Clear the close-on-exec flag for stdin, stdout, and stderr.
+       All other pipe handles will be closed when exec succeeds.  */
+    fcntl(0, F_SETFD, 0);
+    fcntl(1, F_SETFD, 0);
+    fcntl(2, F_SETFD, 0);
+
+    /* Restore all default signal handlers. */
+    kwsysProcessRestoreDefaultSignalHandlers();
+
+    /* Now that we have restored default signal handling and created the
+       process group, restore mask.  */
+    sigprocmask(SIG_SETMASK, &old_mask, 0);
+
+    /* Create new process group.  We use setsid instead of setpgid to avoid
+       the child getting hung up on signals like SIGTTOU.  (In the real world,
+       this has been observed where "git svn" ends up calling the "resize"
+       program which opens /dev/tty.  */
+    if (cp->CreateProcessGroup && setsid() < 0) {
+      kwsysProcessChildErrorExit(si->ErrorPipe[1]);
+    }
+#endif
+
+    /* Execute the real process.  If successful, this does not return.  */
+    execvp(cp->Commands[prIndex][0], cp->Commands[prIndex]);
+    /* TODO: What does VMS do if the child fails to start?  */
+    /* TODO: On VMS, how do we put the process in a new group?  */
+
+    /* Failure.  Report error to parent and terminate.  */
+    kwsysProcessChildErrorExit(si->ErrorPipe[1]);
+  }
+
+#if defined(__VMS)
+  /* Restore the standard pipes of this process.  */
+  decc$set_child_standard_streams(0, 1, 2);
+#endif
+
+  /* We are done with the error reporting pipe and process group setup pipe
+     write end.  */
+  kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+  kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+
+  /* Make sure the child is in the process group before we proceed.  This
+     avoids race conditions with calls to the kill function that we make for
+     signalling process groups.  */
+  while ((readRes = read(pgidPipe[0], &tmp, 1)) > 0)
+    ;
+  if (readRes < 0) {
+    sigprocmask(SIG_SETMASK, &old_mask, 0);
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+    kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+    return 0;
+  }
+  kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+
+  /* Unmask signals.  */
+  if (sigprocmask(SIG_SETMASK, &old_mask, 0) < 0) {
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+    return 0;
+  }
+
+  /* A child has been created.  */
+  ++cp->CommandsLeft;
+
+  /* Block until the child's exec call succeeds and closes the error
+     pipe or writes data to the pipe to report an error.  */
+  {
+    kwsysProcess_ssize_t total = 0;
+    kwsysProcess_ssize_t n = 1;
+    /* Read the entire error message up to the length of our buffer.  */
+    while (total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0) {
+      /* Keep trying to read until the operation is not interrupted.  */
+      while (((n = read(si->ErrorPipe[0], cp->ErrorMessage + total,
+                        (size_t)(KWSYSPE_PIPE_BUFFER_SIZE - total))) < 0) &&
+             (errno == EINTR))
+        ;
+      if (n > 0) {
+        total += n;
+      }
+    }
+
+    /* We are done with the error reporting pipe read end.  */
+    kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+
+    if (total > 0) {
+      /* The child failed to execute the process.  */
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessDestroy(kwsysProcess* cp)
+{
+  /* A child process has terminated.  Reap it if it is one handled by
+     this object.  */
+  int i;
+  /* Temporarily disable signals that access ForkPIDs.  We don't want them to
+     read a reaped PID, and writes to ForkPIDs are not atomic.  */
+  sigset_t mask, old_mask;
+  sigemptyset(&mask);
+  sigaddset(&mask, SIGINT);
+  sigaddset(&mask, SIGTERM);
+  if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
+    return;
+  }
+
+  for (i = 0; i < cp->NumberOfCommands; ++i) {
+    if (cp->ForkPIDs[i]) {
+      int result;
+      while (((result = waitpid(cp->ForkPIDs[i], &cp->CommandExitCodes[i],
+                                WNOHANG)) < 0) &&
+             (errno == EINTR))
+        ;
+      if (result > 0) {
+        /* This child has termianted.  */
+        cp->ForkPIDs[i] = 0;
+        if (--cp->CommandsLeft == 0) {
+          /* All children have terminated.  Close the signal pipe
+             write end so that no more notifications are sent to this
+             object.  */
+          kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+
+          /* TODO: Once the children have terminated, switch
+             WaitForData to use a non-blocking read to get the
+             rest of the data from the pipe.  This is needed when
+             grandchildren keep the output pipes open.  */
+        }
+      } else if (result < 0 && cp->State != kwsysProcess_State_Error) {
+        /* Unexpected error.  Report the first time this happens.  */
+        strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+        cp->State = kwsysProcess_State_Error;
+      }
+    }
+  }
+
+  /* Re-enable signals.  */
+  sigprocmask(SIG_SETMASK, &old_mask, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
+{
+  int fout;
+  if (!name) {
+    return 1;
+  }
+
+  /* Close the existing descriptor.  */
+  kwsysProcessCleanupDescriptor(p);
+
+  /* Open a file for the pipe to write.  */
+  if ((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+    return 0;
+  }
+
+  /* Set close-on-exec flag on the pipe's end.  */
+  if (fcntl(fout, F_SETFD, FD_CLOEXEC) < 0) {
+    return 0;
+  }
+
+  /* Assign the replacement descriptor.  */
+  *p = fout;
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessSetupOutputPipeNative(int* p, int des[2])
+{
+  /* Close the existing descriptor.  */
+  kwsysProcessCleanupDescriptor(p);
+
+  /* Set close-on-exec flag on the pipe's ends.  The proper end will
+     be dup2-ed into the standard descriptor number after fork but
+     before exec.  */
+  if ((fcntl(des[0], F_SETFD, FD_CLOEXEC) < 0) ||
+      (fcntl(des[1], F_SETFD, FD_CLOEXEC) < 0)) {
+    return 0;
+  }
+
+  /* Assign the replacement descriptor.  */
+  *p = des[1];
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the time at which either the process or user timeout will
+   expire.  Returns 1 if the user timeout is first, and 0 otherwise.  */
+static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
+                                      kwsysProcessTime* timeoutTime)
+{
+  /* The first time this is called, we need to calculate the time at
+     which the child will timeout.  */
+  if (cp->Timeout > 0 && cp->TimeoutTime.tv_sec < 0) {
+    kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout);
+    cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length);
+  }
+
+  /* Start with process timeout.  */
+  *timeoutTime = cp->TimeoutTime;
+
+  /* Check if the user timeout is earlier.  */
+  if (userTimeout) {
+    kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
+    kwsysProcessTime userTimeoutLength =
+      kwsysProcessTimeFromDouble(*userTimeout);
+    kwsysProcessTime userTimeoutTime =
+      kwsysProcessTimeAdd(currentTime, userTimeoutLength);
+    if (timeoutTime->tv_sec < 0 ||
+        kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) {
+      *timeoutTime = userTimeoutTime;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the length of time before the given timeout time arrives.
+   Returns 1 if the time has already arrived, and 0 otherwise.  */
+static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
+                                      double* userTimeout,
+                                      kwsysProcessTimeNative* timeoutLength,
+                                      int zeroIsExpired)
+{
+  if (timeoutTime->tv_sec < 0) {
+    /* No timeout time has been requested.  */
+    return 0;
+  } else {
+    /* Calculate the remaining time.  */
+    kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
+    kwsysProcessTime timeLeft =
+      kwsysProcessTimeSubtract(*timeoutTime, currentTime);
+    if (timeLeft.tv_sec < 0 && userTimeout && *userTimeout <= 0) {
+      /* Caller has explicitly requested a zero timeout.  */
+      timeLeft.tv_sec = 0;
+      timeLeft.tv_usec = 0;
+    }
+
+    if (timeLeft.tv_sec < 0 ||
+        (timeLeft.tv_sec == 0 && timeLeft.tv_usec == 0 && zeroIsExpired)) {
+      /* Timeout has already expired.  */
+      return 1;
+    } else {
+      /* There is some time left.  */
+      timeoutLength->tv_sec = timeLeft.tv_sec;
+      timeoutLength->tv_usec = timeLeft.tv_usec;
+      return 0;
+    }
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcessTime kwsysProcessTimeGetCurrent(void)
+{
+  kwsysProcessTime current;
+  kwsysProcessTimeNative current_native;
+  gettimeofday(&current_native, 0);
+  current.tv_sec = (long)current_native.tv_sec;
+  current.tv_usec = (long)current_native.tv_usec;
+  return current;
+}
+
+/*--------------------------------------------------------------------------*/
+static double kwsysProcessTimeToDouble(kwsysProcessTime t)
+{
+  return (double)t.tv_sec + (double)(t.tv_usec) * 0.000001;
+}
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcessTime kwsysProcessTimeFromDouble(double d)
+{
+  kwsysProcessTime t;
+  t.tv_sec = (long)d;
+  t.tv_usec = (long)((d - (double)(t.tv_sec)) * 1000000);
+  return t;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2)
+{
+  return ((in1.tv_sec < in2.tv_sec) ||
+          ((in1.tv_sec == in2.tv_sec) && (in1.tv_usec < in2.tv_usec)));
+}
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
+                                            kwsysProcessTime in2)
+{
+  kwsysProcessTime out;
+  out.tv_sec = in1.tv_sec + in2.tv_sec;
+  out.tv_usec = in1.tv_usec + in2.tv_usec;
+  if (out.tv_usec >= 1000000) {
+    out.tv_usec -= 1000000;
+    out.tv_sec += 1;
+  }
+  return out;
+}
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
+                                                 kwsysProcessTime in2)
+{
+  kwsysProcessTime out;
+  out.tv_sec = in1.tv_sec - in2.tv_sec;
+  out.tv_usec = in1.tv_usec - in2.tv_usec;
+  if (out.tv_usec < 0) {
+    out.tv_usec += 1000000;
+    out.tv_sec -= 1;
+  }
+  return out;
+}
+
+/*--------------------------------------------------------------------------*/
+#define KWSYSPE_CASE(type, str)                                               \
+  cp->ExitException = kwsysProcess_Exception_##type;                          \
+  strcpy(cp->ExitExceptionString, str)
+static void kwsysProcessSetExitException(kwsysProcess* cp, int sig)
+{
+  switch (sig) {
+#ifdef SIGSEGV
+    case SIGSEGV:
+      KWSYSPE_CASE(Fault, "Segmentation fault");
+      break;
+#endif
+#ifdef SIGBUS
+#if !defined(SIGSEGV) || SIGBUS != SIGSEGV
+    case SIGBUS:
+      KWSYSPE_CASE(Fault, "Bus error");
+      break;
+#endif
+#endif
+#ifdef SIGFPE
+    case SIGFPE:
+      KWSYSPE_CASE(Numerical, "Floating-point exception");
+      break;
+#endif
+#ifdef SIGILL
+    case SIGILL:
+      KWSYSPE_CASE(Illegal, "Illegal instruction");
+      break;
+#endif
+#ifdef SIGINT
+    case SIGINT:
+      KWSYSPE_CASE(Interrupt, "User interrupt");
+      break;
+#endif
+#ifdef SIGABRT
+    case SIGABRT:
+      KWSYSPE_CASE(Other, "Child aborted");
+      break;
+#endif
+#ifdef SIGKILL
+    case SIGKILL:
+      KWSYSPE_CASE(Other, "Child killed");
+      break;
+#endif
+#ifdef SIGTERM
+    case SIGTERM:
+      KWSYSPE_CASE(Other, "Child terminated");
+      break;
+#endif
+#ifdef SIGHUP
+    case SIGHUP:
+      KWSYSPE_CASE(Other, "SIGHUP");
+      break;
+#endif
+#ifdef SIGQUIT
+    case SIGQUIT:
+      KWSYSPE_CASE(Other, "SIGQUIT");
+      break;
+#endif
+#ifdef SIGTRAP
+    case SIGTRAP:
+      KWSYSPE_CASE(Other, "SIGTRAP");
+      break;
+#endif
+#ifdef SIGIOT
+#if !defined(SIGABRT) || SIGIOT != SIGABRT
+    case SIGIOT:
+      KWSYSPE_CASE(Other, "SIGIOT");
+      break;
+#endif
+#endif
+#ifdef SIGUSR1
+    case SIGUSR1:
+      KWSYSPE_CASE(Other, "SIGUSR1");
+      break;
+#endif
+#ifdef SIGUSR2
+    case SIGUSR2:
+      KWSYSPE_CASE(Other, "SIGUSR2");
+      break;
+#endif
+#ifdef SIGPIPE
+    case SIGPIPE:
+      KWSYSPE_CASE(Other, "SIGPIPE");
+      break;
+#endif
+#ifdef SIGALRM
+    case SIGALRM:
+      KWSYSPE_CASE(Other, "SIGALRM");
+      break;
+#endif
+#ifdef SIGSTKFLT
+    case SIGSTKFLT:
+      KWSYSPE_CASE(Other, "SIGSTKFLT");
+      break;
+#endif
+#ifdef SIGCHLD
+    case SIGCHLD:
+      KWSYSPE_CASE(Other, "SIGCHLD");
+      break;
+#elif defined(SIGCLD)
+    case SIGCLD:
+      KWSYSPE_CASE(Other, "SIGCLD");
+      break;
+#endif
+#ifdef SIGCONT
+    case SIGCONT:
+      KWSYSPE_CASE(Other, "SIGCONT");
+      break;
+#endif
+#ifdef SIGSTOP
+    case SIGSTOP:
+      KWSYSPE_CASE(Other, "SIGSTOP");
+      break;
+#endif
+#ifdef SIGTSTP
+    case SIGTSTP:
+      KWSYSPE_CASE(Other, "SIGTSTP");
+      break;
+#endif
+#ifdef SIGTTIN
+    case SIGTTIN:
+      KWSYSPE_CASE(Other, "SIGTTIN");
+      break;
+#endif
+#ifdef SIGTTOU
+    case SIGTTOU:
+      KWSYSPE_CASE(Other, "SIGTTOU");
+      break;
+#endif
+#ifdef SIGURG
+    case SIGURG:
+      KWSYSPE_CASE(Other, "SIGURG");
+      break;
+#endif
+#ifdef SIGXCPU
+    case SIGXCPU:
+      KWSYSPE_CASE(Other, "SIGXCPU");
+      break;
+#endif
+#ifdef SIGXFSZ
+    case SIGXFSZ:
+      KWSYSPE_CASE(Other, "SIGXFSZ");
+      break;
+#endif
+#ifdef SIGVTALRM
+    case SIGVTALRM:
+      KWSYSPE_CASE(Other, "SIGVTALRM");
+      break;
+#endif
+#ifdef SIGPROF
+    case SIGPROF:
+      KWSYSPE_CASE(Other, "SIGPROF");
+      break;
+#endif
+#ifdef SIGWINCH
+    case SIGWINCH:
+      KWSYSPE_CASE(Other, "SIGWINCH");
+      break;
+#endif
+#ifdef SIGPOLL
+    case SIGPOLL:
+      KWSYSPE_CASE(Other, "SIGPOLL");
+      break;
+#endif
+#ifdef SIGIO
+#if !defined(SIGPOLL) || SIGIO != SIGPOLL
+    case SIGIO:
+      KWSYSPE_CASE(Other, "SIGIO");
+      break;
+#endif
+#endif
+#ifdef SIGPWR
+    case SIGPWR:
+      KWSYSPE_CASE(Other, "SIGPWR");
+      break;
+#endif
+#ifdef SIGSYS
+    case SIGSYS:
+      KWSYSPE_CASE(Other, "SIGSYS");
+      break;
+#endif
+#ifdef SIGUNUSED
+#if !defined(SIGSYS) || SIGUNUSED != SIGSYS
+    case SIGUNUSED:
+      KWSYSPE_CASE(Other, "SIGUNUSED");
+      break;
+#endif
+#endif
+    default:
+      cp->ExitException = kwsysProcess_Exception_Other;
+      sprintf(cp->ExitExceptionString, "Signal %d", sig);
+      break;
+  }
+}
+#undef KWSYSPE_CASE
+
+/*--------------------------------------------------------------------------*/
+/* When the child process encounters an error before its program is
+   invoked, this is called to report the error to the parent and
+   exit.  */
+static void kwsysProcessChildErrorExit(int errorPipe)
+{
+  /* Construct the error message.  */
+  char buffer[KWSYSPE_PIPE_BUFFER_SIZE];
+  kwsysProcess_ssize_t result;
+  strncpy(buffer, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
+
+  /* Report the error to the parent through the special pipe.  */
+  result = write(errorPipe, buffer, strlen(buffer));
+  (void)result;
+
+  /* Terminate without cleanup.  */
+  _exit(1);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Restores all signal handlers to their default values.  */
+static void kwsysProcessRestoreDefaultSignalHandlers(void)
+{
+  struct sigaction act;
+  memset(&act, 0, sizeof(struct sigaction));
+  act.sa_handler = SIG_DFL;
+#ifdef SIGHUP
+  sigaction(SIGHUP, &act, 0);
+#endif
+#ifdef SIGINT
+  sigaction(SIGINT, &act, 0);
+#endif
+#ifdef SIGQUIT
+  sigaction(SIGQUIT, &act, 0);
+#endif
+#ifdef SIGILL
+  sigaction(SIGILL, &act, 0);
+#endif
+#ifdef SIGTRAP
+  sigaction(SIGTRAP, &act, 0);
+#endif
+#ifdef SIGABRT
+  sigaction(SIGABRT, &act, 0);
+#endif
+#ifdef SIGIOT
+  sigaction(SIGIOT, &act, 0);
+#endif
+#ifdef SIGBUS
+  sigaction(SIGBUS, &act, 0);
+#endif
+#ifdef SIGFPE
+  sigaction(SIGFPE, &act, 0);
+#endif
+#ifdef SIGUSR1
+  sigaction(SIGUSR1, &act, 0);
+#endif
+#ifdef SIGSEGV
+  sigaction(SIGSEGV, &act, 0);
+#endif
+#ifdef SIGUSR2
+  sigaction(SIGUSR2, &act, 0);
+#endif
+#ifdef SIGPIPE
+  sigaction(SIGPIPE, &act, 0);
+#endif
+#ifdef SIGALRM
+  sigaction(SIGALRM, &act, 0);
+#endif
+#ifdef SIGTERM
+  sigaction(SIGTERM, &act, 0);
+#endif
+#ifdef SIGSTKFLT
+  sigaction(SIGSTKFLT, &act, 0);
+#endif
+#ifdef SIGCLD
+  sigaction(SIGCLD, &act, 0);
+#endif
+#ifdef SIGCHLD
+  sigaction(SIGCHLD, &act, 0);
+#endif
+#ifdef SIGCONT
+  sigaction(SIGCONT, &act, 0);
+#endif
+#ifdef SIGTSTP
+  sigaction(SIGTSTP, &act, 0);
+#endif
+#ifdef SIGTTIN
+  sigaction(SIGTTIN, &act, 0);
+#endif
+#ifdef SIGTTOU
+  sigaction(SIGTTOU, &act, 0);
+#endif
+#ifdef SIGURG
+  sigaction(SIGURG, &act, 0);
+#endif
+#ifdef SIGXCPU
+  sigaction(SIGXCPU, &act, 0);
+#endif
+#ifdef SIGXFSZ
+  sigaction(SIGXFSZ, &act, 0);
+#endif
+#ifdef SIGVTALRM
+  sigaction(SIGVTALRM, &act, 0);
+#endif
+#ifdef SIGPROF
+  sigaction(SIGPROF, &act, 0);
+#endif
+#ifdef SIGWINCH
+  sigaction(SIGWINCH, &act, 0);
+#endif
+#ifdef SIGPOLL
+  sigaction(SIGPOLL, &act, 0);
+#endif
+#ifdef SIGIO
+  sigaction(SIGIO, &act, 0);
+#endif
+#ifdef SIGPWR
+  sigaction(SIGPWR, &act, 0);
+#endif
+#ifdef SIGSYS
+  sigaction(SIGSYS, &act, 0);
+#endif
+#ifdef SIGUNUSED
+  sigaction(SIGUNUSED, &act, 0);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessExit(void)
+{
+  _exit(0);
+}
+
+/*--------------------------------------------------------------------------*/
+#if !defined(__VMS)
+static pid_t kwsysProcessFork(kwsysProcess* cp,
+                              kwsysProcessCreateInformation* si)
+{
+  /* Create a detached process if requested.  */
+  if (cp->OptionDetach) {
+    /* Create an intermediate process.  */
+    pid_t middle_pid = fork();
+    if (middle_pid < 0) {
+      /* Fork failed.  Return as if we were not detaching.  */
+      return middle_pid;
+    } else if (middle_pid == 0) {
+      /* This is the intermediate process.  Create the real child.  */
+      pid_t child_pid = fork();
+      if (child_pid == 0) {
+        /* This is the real child process.  There is nothing to do here.  */
+        return 0;
+      } else {
+        /* Use the error pipe to report the pid to the real parent.  */
+        while ((write(si->ErrorPipe[1], &child_pid, sizeof(child_pid)) < 0) &&
+               (errno == EINTR))
+          ;
+
+        /* Exit without cleanup.  The parent holds all resources.  */
+        kwsysProcessExit();
+        return 0; /* Never reached, but avoids SunCC warning.  */
+      }
+    } else {
+      /* This is the original parent process.  The intermediate
+         process will use the error pipe to report the pid of the
+         detached child.  */
+      pid_t child_pid;
+      int status;
+      while ((read(si->ErrorPipe[0], &child_pid, sizeof(child_pid)) < 0) &&
+             (errno == EINTR))
+        ;
+
+      /* Wait for the intermediate process to exit and clean it up.  */
+      while ((waitpid(middle_pid, &status, 0) < 0) && (errno == EINTR))
+        ;
+      return child_pid;
+    }
+  } else {
+    /* Not creating a detached process.  Use normal fork.  */
+    return fork();
+  }
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* We try to obtain process information by invoking the ps command.
+   Here we define the command to call on each platform and the
+   corresponding parsing format string.  The parsing format should
+   have two integers to store: the pid and then the ppid.  */
+#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||       \
+  defined(__OpenBSD__) || defined(__GLIBC__) || defined(__GNU__)
+#define KWSYSPE_PS_COMMAND "ps axo pid,ppid"
+#define KWSYSPE_PS_FORMAT "%d %d\n"
+#elif defined(__sun) && (defined(__SVR4) || defined(__svr4__)) /* Solaris */
+#define KWSYSPE_PS_COMMAND "ps -e -o pid,ppid"
+#define KWSYSPE_PS_FORMAT "%d %d\n"
+#elif defined(__hpux) || defined(__sun__) || defined(__sgi) ||                \
+  defined(_AIX) || defined(__sparc)
+#define KWSYSPE_PS_COMMAND "ps -ef"
+#define KWSYSPE_PS_FORMAT "%*s %d %d %*[^\n]\n"
+#elif defined(__QNX__)
+#define KWSYSPE_PS_COMMAND "ps -Af"
+#define KWSYSPE_PS_FORMAT "%*d %d %d %*[^\n]\n"
+#elif defined(__CYGWIN__)
+#define KWSYSPE_PS_COMMAND "ps aux"
+#define KWSYSPE_PS_FORMAT "%d %d %*[^\n]\n"
+#endif
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessKill(pid_t process_id)
+{
+#if defined(__linux__) || defined(__CYGWIN__)
+  DIR* procdir;
+#endif
+
+  /* Suspend the process to be sure it will not create more children.  */
+  kill(process_id, SIGSTOP);
+
+#if defined(__CYGWIN__)
+  /* Some Cygwin versions seem to need help here.  Give up our time slice
+     so that the child can process SIGSTOP before we send SIGKILL.  */
+  usleep(1);
+#endif
+
+/* Kill all children if we can find them.  */
+#if defined(__linux__) || defined(__CYGWIN__)
+  /* First try using the /proc filesystem.  */
+  if ((procdir = opendir("/proc")) != NULL) {
+#if defined(MAXPATHLEN)
+    char fname[MAXPATHLEN];
+#elif defined(PATH_MAX)
+    char fname[PATH_MAX];
+#else
+    char fname[4096];
+#endif
+    char buffer[KWSYSPE_PIPE_BUFFER_SIZE + 1];
+    struct dirent* d;
+
+    /* Each process has a directory in /proc whose name is the pid.
+       Within this directory is a file called stat that has the
+       following format:
+
+         pid (command line) status ppid ...
+
+       We want to get the ppid for all processes.  Those that have
+       process_id as their parent should be recursively killed.  */
+    for (d = readdir(procdir); d; d = readdir(procdir)) {
+      int pid;
+      if (sscanf(d->d_name, "%d", &pid) == 1 && pid != 0) {
+        struct stat finfo;
+        sprintf(fname, "/proc/%d/stat", pid);
+        if (stat(fname, &finfo) == 0) {
+          FILE* f = fopen(fname, "r");
+          if (f) {
+            size_t nread = fread(buffer, 1, KWSYSPE_PIPE_BUFFER_SIZE, f);
+            fclose(f);
+            buffer[nread] = '\0';
+            if (nread > 0) {
+              const char* rparen = strrchr(buffer, ')');
+              int ppid;
+              if (rparen && (sscanf(rparen + 1, "%*s %d", &ppid) == 1)) {
+                if (ppid == process_id) {
+                  /* Recursively kill this child and its children.  */
+                  kwsysProcessKill(pid);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    closedir(procdir);
+  } else
+#endif
+  {
+#if defined(KWSYSPE_PS_COMMAND)
+    /* Try running "ps" to get the process information.  */
+    FILE* ps = popen(KWSYSPE_PS_COMMAND, "r");
+
+    /* Make sure the process started and provided a valid header.  */
+    if (ps && fscanf(ps, "%*[^\n]\n") != EOF) {
+      /* Look for processes whose parent is the process being killed.  */
+      int pid, ppid;
+      while (fscanf(ps, KWSYSPE_PS_FORMAT, &pid, &ppid) == 2) {
+        if (ppid == process_id) {
+          /* Recursively kill this child and its children.  */
+          kwsysProcessKill(pid);
+        }
+      }
+    }
+
+    /* We are done with the ps process.  */
+    if (ps) {
+      pclose(ps);
+    }
+#endif
+  }
+
+  /* Kill the process.  */
+  kill(process_id, SIGKILL);
+
+#if defined(__APPLE__)
+  /* On OS X 10.3 the above SIGSTOP occasionally prevents the SIGKILL
+     from working.  Just in case, we resume the child and kill it
+     again.  There is a small race condition in this obscure case.  If
+     the child manages to fork again between these two signals, we
+     will not catch its children.  */
+  kill(process_id, SIGCONT);
+  kill(process_id, SIGKILL);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+#if defined(__VMS)
+int decc$feature_get_index(const char* name);
+int decc$feature_set_value(int index, int mode, int value);
+static int kwsysProcessSetVMSFeature(const char* name, int value)
+{
+  int i;
+  errno = 0;
+  i = decc$feature_get_index(name);
+  return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0);
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Global set of executing processes for use by the signal handler.
+   This global instance will be zero-initialized by the compiler.  */
+typedef struct kwsysProcessInstances_s
+{
+  int Count;
+  int Size;
+  kwsysProcess** Processes;
+} kwsysProcessInstances;
+static kwsysProcessInstances kwsysProcesses;
+
+/* The old SIGCHLD / SIGINT / SIGTERM handlers.  */
+static struct sigaction kwsysProcessesOldSigChldAction;
+static struct sigaction kwsysProcessesOldSigIntAction;
+static struct sigaction kwsysProcessesOldSigTermAction;
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses)
+{
+  /* Block signals while we update the set of pipes to check.
+     TODO: sigprocmask is undefined for threaded apps.  See
+     pthread_sigmask.  */
+  sigset_t newset;
+  sigset_t oldset;
+  sigemptyset(&newset);
+  sigaddset(&newset, SIGCHLD);
+  sigaddset(&newset, SIGINT);
+  sigaddset(&newset, SIGTERM);
+  sigprocmask(SIG_BLOCK, &newset, &oldset);
+
+  /* Store the new set in that seen by the signal handler.  */
+  kwsysProcesses = *newProcesses;
+
+  /* Restore the signal mask to the previous setting.  */
+  sigprocmask(SIG_SETMASK, &oldset, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcessesAdd(kwsysProcess* cp)
+{
+  /* Create a pipe through which the signal handler can notify the
+     given process object that a child has exited.  */
+  {
+    /* Create the pipe.  */
+    int p[2];
+    if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) {
+      return 0;
+    }
+
+    /* Store the pipes now to be sure they are cleaned up later.  */
+    cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL] = p[0];
+    cp->SignalPipe = p[1];
+
+    /* Switch the pipe to non-blocking mode so that reading a byte can
+       be an atomic test-and-set.  */
+    if (!kwsysProcessSetNonBlocking(p[0]) ||
+        !kwsysProcessSetNonBlocking(p[1])) {
+      return 0;
+    }
+
+    /* The children do not need this pipe.  Set close-on-exec flag on
+       the pipe's ends.  */
+    if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
+        (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) {
+      return 0;
+    }
+  }
+
+  /* Attempt to add the given signal pipe to the signal handler set.  */
+  {
+
+    /* Make sure there is enough space for the new signal pipe.  */
+    kwsysProcessInstances oldProcesses = kwsysProcesses;
+    kwsysProcessInstances newProcesses = oldProcesses;
+    if (oldProcesses.Count == oldProcesses.Size) {
+      /* Start with enough space for a small number of process instances
+         and double the size each time more is needed.  */
+      newProcesses.Size = oldProcesses.Size ? oldProcesses.Size * 2 : 4;
+
+      /* Try allocating the new block of memory.  */
+      if ((newProcesses.Processes = ((kwsysProcess**)malloc(
+             (size_t)(newProcesses.Size) * sizeof(kwsysProcess*))))) {
+        /* Copy the old pipe set to the new memory.  */
+        if (oldProcesses.Count > 0) {
+          memcpy(newProcesses.Processes, oldProcesses.Processes,
+                 ((size_t)(oldProcesses.Count) * sizeof(kwsysProcess*)));
+        }
+      } else {
+        /* Failed to allocate memory for the new signal pipe set.  */
+        return 0;
+      }
+    }
+
+    /* Append the new signal pipe to the set.  */
+    newProcesses.Processes[newProcesses.Count++] = cp;
+
+    /* Store the new set in that seen by the signal handler.  */
+    kwsysProcessesUpdate(&newProcesses);
+
+    /* Free the original pipes if new ones were allocated.  */
+    if (newProcesses.Processes != oldProcesses.Processes) {
+      free(oldProcesses.Processes);
+    }
+
+    /* If this is the first process, enable the signal handler.  */
+    if (newProcesses.Count == 1) {
+      /* Install our handler for SIGCHLD.  Repeat call until it is not
+         interrupted.  */
+      struct sigaction newSigAction;
+      memset(&newSigAction, 0, sizeof(struct sigaction));
+#if KWSYSPE_USE_SIGINFO
+      newSigAction.sa_sigaction = kwsysProcessesSignalHandler;
+      newSigAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
+#ifdef SA_RESTART
+      newSigAction.sa_flags |= SA_RESTART;
+#endif
+#else
+      newSigAction.sa_handler = kwsysProcessesSignalHandler;
+      newSigAction.sa_flags = SA_NOCLDSTOP;
+#endif
+      sigemptyset(&newSigAction.sa_mask);
+      while ((sigaction(SIGCHLD, &newSigAction,
+                        &kwsysProcessesOldSigChldAction) < 0) &&
+             (errno == EINTR))
+        ;
+
+      /* Install our handler for SIGINT / SIGTERM.  Repeat call until
+         it is not interrupted.  */
+      sigemptyset(&newSigAction.sa_mask);
+      sigaddset(&newSigAction.sa_mask, SIGTERM);
+      while ((sigaction(SIGINT, &newSigAction,
+                        &kwsysProcessesOldSigIntAction) < 0) &&
+             (errno == EINTR))
+        ;
+
+      sigemptyset(&newSigAction.sa_mask);
+      sigaddset(&newSigAction.sa_mask, SIGINT);
+      while ((sigaction(SIGTERM, &newSigAction,
+                        &kwsysProcessesOldSigIntAction) < 0) &&
+             (errno == EINTR))
+        ;
+    }
+  }
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesRemove(kwsysProcess* cp)
+{
+  /* Attempt to remove the given signal pipe from the signal handler set.  */
+  {
+    /* Find the given process in the set.  */
+    kwsysProcessInstances newProcesses = kwsysProcesses;
+    int i;
+    for (i = 0; i < newProcesses.Count; ++i) {
+      if (newProcesses.Processes[i] == cp) {
+        break;
+      }
+    }
+    if (i < newProcesses.Count) {
+      /* Remove the process from the set.  */
+      --newProcesses.Count;
+      for (; i < newProcesses.Count; ++i) {
+        newProcesses.Processes[i] = newProcesses.Processes[i + 1];
+      }
+
+      /* If this was the last process, disable the signal handler.  */
+      if (newProcesses.Count == 0) {
+        /* Restore the signal handlers.  Repeat call until it is not
+           interrupted.  */
+        while ((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) &&
+               (errno == EINTR))
+          ;
+        while ((sigaction(SIGINT, &kwsysProcessesOldSigIntAction, 0) < 0) &&
+               (errno == EINTR))
+          ;
+        while ((sigaction(SIGTERM, &kwsysProcessesOldSigTermAction, 0) < 0) &&
+               (errno == EINTR))
+          ;
+
+        /* Free the table of process pointers since it is now empty.
+           This is safe because the signal handler has been removed.  */
+        newProcesses.Size = 0;
+        free(newProcesses.Processes);
+        newProcesses.Processes = 0;
+      }
+
+      /* Store the new set in that seen by the signal handler.  */
+      kwsysProcessesUpdate(&newProcesses);
+    }
+  }
+
+  /* Close the pipe through which the signal handler may have notified
+     the given process object that a child has exited.  */
+  kwsysProcessCleanupDescriptor(&cp->SignalPipe);
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessesSignalHandler(int signum
+#if KWSYSPE_USE_SIGINFO
+                                        ,
+                                        siginfo_t* info, void* ucontext
+#endif
+                                        )
+{
+  int i, j, procStatus, old_errno = errno;
+#if KWSYSPE_USE_SIGINFO
+  (void)info;
+  (void)ucontext;
+#endif
+
+  /* Signal all process objects that a child has terminated.  */
+  switch (signum) {
+    case SIGCHLD:
+      for (i = 0; i < kwsysProcesses.Count; ++i) {
+        /* Set the pipe in a signalled state.  */
+        char buf = 1;
+        kwsysProcess* cp = kwsysProcesses.Processes[i];
+        kwsysProcess_ssize_t pipeStatus =
+          read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1);
+        (void)pipeStatus;
+        pipeStatus = write(cp->SignalPipe, &buf, 1);
+        (void)pipeStatus;
+      }
+      break;
+    case SIGINT:
+    case SIGTERM:
+      /* Signal child processes that are running in new process groups.  */
+      for (i = 0; i < kwsysProcesses.Count; ++i) {
+        kwsysProcess* cp = kwsysProcesses.Processes[i];
+        /* Check Killed to avoid data race condition when killing.
+           Check State to avoid data race condition in kwsysProcessCleanup
+           when there is an error (it leaves a reaped PID).  */
+        if (cp->CreateProcessGroup && !cp->Killed &&
+            cp->State != kwsysProcess_State_Error && cp->ForkPIDs) {
+          for (j = 0; j < cp->NumberOfCommands; ++j) {
+            /* Make sure the PID is still valid. */
+            if (cp->ForkPIDs[j]) {
+              /* The user created a process group for this process.  The group
+                 ID
+                 is the process ID for the original process in the group.  */
+              kill(-cp->ForkPIDs[j], SIGINT);
+            }
+          }
+        }
+      }
+
+      /* Wait for all processes to terminate.  */
+      while (wait(&procStatus) >= 0 || errno != ECHILD) {
+      }
+
+      /* Terminate the process, which is now in an inconsistent state
+         because we reaped all the PIDs that it may have been reaping
+         or may have reaped in the future.  Reraise the signal so that
+         the proper exit code is returned.  */
+      {
+        /* Install default signal handler.  */
+        struct sigaction defSigAction;
+        sigset_t unblockSet;
+        memset(&defSigAction, 0, sizeof(defSigAction));
+        defSigAction.sa_handler = SIG_DFL;
+        sigemptyset(&defSigAction.sa_mask);
+        while ((sigaction(signum, &defSigAction, 0) < 0) && (errno == EINTR))
+          ;
+        /* Unmask the signal.  */
+        sigemptyset(&unblockSet);
+        sigaddset(&unblockSet, signum);
+        sigprocmask(SIG_UNBLOCK, &unblockSet, 0);
+        /* Raise the signal again.  */
+        raise(signum);
+        /* We shouldn't get here... but if we do... */
+        _exit(1);
+      }
+      /* break omitted to silence unreachable code clang compiler warning.  */
+  }
+
+#if !KWSYSPE_USE_SIGINFO
+  /* Re-Install our handler.  Repeat call until it is not interrupted.  */
+  {
+    struct sigaction newSigAction;
+    struct sigaction& oldSigAction;
+    memset(&newSigAction, 0, sizeof(struct sigaction));
+    newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
+    newSigChldAction.sa_flags = SA_NOCLDSTOP;
+    sigemptyset(&newSigAction.sa_mask);
+    switch (signum) {
+      case SIGCHLD:
+        oldSigAction = &kwsysProcessesOldSigChldAction;
+        break;
+      case SIGINT:
+        sigaddset(&newSigAction.sa_mask, SIGTERM);
+        oldSigAction = &kwsysProcessesOldSigIntAction;
+        break;
+      case SIGTERM:
+        sigaddset(&newSigAction.sa_mask, SIGINT);
+        oldSigAction = &kwsysProcessesOldSigTermAction;
+        break;
+      default:
+        return 0;
+    }
+    while ((sigaction(signum, &newSigAction, oldSigAction) < 0) &&
+           (errno == EINTR))
+      ;
+  }
+#endif
+
+  errno = old_errno;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_ResetStartTime(kwsysProcess* cp)
+{
+  if (!cp) {
+    return;
+  }
+  /* Reset start time. */
+  cp->StartTime = kwsysProcessTimeGetCurrent();
+}
diff --git a/thirdparty/KWSys/adios2sys/ProcessWin32.c b/thirdparty/KWSys/adios2sys/ProcessWin32.c
new file mode 100644
index 0000000000000000000000000000000000000000..d10c7339a7b134a763f696a1261205e943e04e4e
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/ProcessWin32.c
@@ -0,0 +1,2785 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Process.h)
+#include KWSYS_HEADER(Encoding.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "Encoding.h.in"
+#include "Process.h.in"
+#endif
+
+/*
+
+Implementation for Windows
+
+On windows, a thread is created to wait for data on each pipe.  The
+threads are synchronized with the main thread to simulate the use of
+a UNIX-style select system call.
+
+*/
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+#include <windows.h> /* Windows API */
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#endif
+#include <io.h>     /* _unlink */
+#include <stdio.h>  /* sprintf */
+#include <string.h> /* strlen, strdup */
+#ifdef __WATCOMC__
+#define _unlink unlink
+#endif
+
+#ifndef _MAX_FNAME
+#define _MAX_FNAME 4096
+#endif
+#ifndef _MAX_PATH
+#define _MAX_PATH 4096
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#pragma warning(disable : 4514)
+#pragma warning(disable : 4706)
+#endif
+
+#if defined(__BORLANDC__)
+#pragma warn - 8004 /* assigned a value that is never used  */
+#pragma warn - 8060 /* Assignment inside if() condition.  */
+#endif
+
+/* There are pipes for the process pipeline's stdout and stderr.  */
+#define KWSYSPE_PIPE_COUNT 2
+#define KWSYSPE_PIPE_STDOUT 0
+#define KWSYSPE_PIPE_STDERR 1
+
+/* The maximum amount to read from a pipe at a time.  */
+#define KWSYSPE_PIPE_BUFFER_SIZE 1024
+
+/* Debug output macro.  */
+#if 0
+#define KWSYSPE_DEBUG(x)                                                      \
+  ((void*)cp == (void*)0x00226DE0                                             \
+     ? (fprintf(stderr, "%d/%p/%d ", (int)GetCurrentProcessId(), cp,          \
+                __LINE__),                                                    \
+        fprintf x, fflush(stderr), 1)                                         \
+     : (1))
+#else
+#define KWSYSPE_DEBUG(x) (void)1
+#endif
+
+typedef LARGE_INTEGER kwsysProcessTime;
+
+typedef struct kwsysProcessCreateInformation_s
+{
+  /* Windows child startup control data.  */
+  STARTUPINFOW StartupInfo;
+
+  /* Original handles before making inherited duplicates.  */
+  HANDLE hStdInput;
+  HANDLE hStdOutput;
+  HANDLE hStdError;
+} kwsysProcessCreateInformation;
+
+/*--------------------------------------------------------------------------*/
+typedef struct kwsysProcessPipeData_s kwsysProcessPipeData;
+static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd);
+static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp,
+                                           kwsysProcessPipeData* td);
+static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd);
+static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp,
+                                           kwsysProcessPipeData* td);
+static int kwsysProcessInitialize(kwsysProcess* cp);
+static DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
+                                kwsysProcessCreateInformation* si);
+static void kwsysProcessDestroy(kwsysProcess* cp, int event);
+static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
+static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
+static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle);
+static void kwsysProcessCleanupHandle(PHANDLE h);
+static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error);
+static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
+static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
+                                      kwsysProcessTime* timeoutTime);
+static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
+                                      double* userTimeout,
+                                      kwsysProcessTime* timeoutLength);
+static kwsysProcessTime kwsysProcessTimeGetCurrent(void);
+static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t);
+static double kwsysProcessTimeToDouble(kwsysProcessTime t);
+static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
+static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
+static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
+                                            kwsysProcessTime in2);
+static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
+                                                 kwsysProcessTime in2);
+static void kwsysProcessSetExitException(kwsysProcess* cp, int code);
+static void kwsysProcessKillTree(int pid);
+static void kwsysProcessDisablePipeThreads(kwsysProcess* cp);
+static int kwsysProcessesInitialize(void);
+static int kwsysTryEnterCreateProcessSection(void);
+static void kwsysLeaveCreateProcessSection(void);
+static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId,
+                             int newProcessGroup);
+static void kwsysProcessesRemove(HANDLE hProcess);
+static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType);
+
+/*--------------------------------------------------------------------------*/
+/* A structure containing synchronization data for each thread.  */
+typedef struct kwsysProcessPipeSync_s kwsysProcessPipeSync;
+struct kwsysProcessPipeSync_s
+{
+  /* Handle to the thread.  */
+  HANDLE Thread;
+
+  /* Semaphore indicating to the thread that a process has started.  */
+  HANDLE Ready;
+
+  /* Semaphore indicating to the thread that it should begin work.  */
+  HANDLE Go;
+
+  /* Semaphore indicating thread has reset for another process.  */
+  HANDLE Reset;
+};
+
+/*--------------------------------------------------------------------------*/
+/* A structure containing data for each pipe's threads.  */
+struct kwsysProcessPipeData_s
+{
+  /* ------------- Data managed per instance of kwsysProcess ------------- */
+
+  /* Synchronization data for reading thread.  */
+  kwsysProcessPipeSync Reader;
+
+  /* Synchronization data for waking thread.  */
+  kwsysProcessPipeSync Waker;
+
+  /* Index of this pipe.  */
+  int Index;
+
+  /* The kwsysProcess instance owning this pipe.  */
+  kwsysProcess* Process;
+
+  /* ------------- Data managed per call to Execute ------------- */
+
+  /* Buffer for data read in this pipe's thread.  */
+  char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
+
+  /* The length of the data stored in the buffer.  */
+  DWORD DataLength;
+
+  /* Whether the pipe has been closed.  */
+  int Closed;
+
+  /* Handle for the read end of this pipe. */
+  HANDLE Read;
+
+  /* Handle for the write end of this pipe. */
+  HANDLE Write;
+};
+
+/*--------------------------------------------------------------------------*/
+/* Structure containing data used to implement the child's execution.  */
+struct kwsysProcess_s
+{
+  /* ------------- Data managed per instance of kwsysProcess ------------- */
+
+  /* The status of the process structure.  */
+  int State;
+
+  /* The command lines to execute.  */
+  wchar_t** Commands;
+  int NumberOfCommands;
+
+  /* The exit code of each command.  */
+  DWORD* CommandExitCodes;
+
+  /* The working directory for the child process.  */
+  wchar_t* WorkingDirectory;
+
+  /* Whether to create the child as a detached process.  */
+  int OptionDetach;
+
+  /* Whether the child was created as a detached process.  */
+  int Detached;
+
+  /* Whether to hide the child process's window.  */
+  int HideWindow;
+
+  /* Whether to treat command lines as verbatim.  */
+  int Verbatim;
+
+  /* Whether to merge stdout/stderr of the child.  */
+  int MergeOutput;
+
+  /* Whether to create the process in a new process group.  */
+  int CreateProcessGroup;
+
+  /* Mutex to protect the shared index used by threads to report data.  */
+  HANDLE SharedIndexMutex;
+
+  /* Semaphore used by threads to signal data ready.  */
+  HANDLE Full;
+
+  /* Whether we are currently deleting this kwsysProcess instance.  */
+  int Deleting;
+
+  /* Data specific to each pipe and its thread.  */
+  kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT];
+
+  /* Name of files to which stdin and stdout pipes are attached.  */
+  char* PipeFileSTDIN;
+  char* PipeFileSTDOUT;
+  char* PipeFileSTDERR;
+
+  /* Whether each pipe is shared with the parent process.  */
+  int PipeSharedSTDIN;
+  int PipeSharedSTDOUT;
+  int PipeSharedSTDERR;
+
+  /* Native pipes provided by the user.  */
+  HANDLE PipeNativeSTDIN[2];
+  HANDLE PipeNativeSTDOUT[2];
+  HANDLE PipeNativeSTDERR[2];
+
+  /* ------------- Data managed per call to Execute ------------- */
+
+  /* The exceptional behavior that terminated the process, if any.  */
+  int ExitException;
+
+  /* The process exit code.  */
+  DWORD ExitCode;
+
+  /* The process return code, if any.  */
+  int ExitValue;
+
+  /* Index of last pipe to report data, if any.  */
+  int CurrentIndex;
+
+  /* Index shared by threads to report data.  */
+  int SharedIndex;
+
+  /* The timeout length.  */
+  double Timeout;
+
+  /* Time at which the child started.  */
+  kwsysProcessTime StartTime;
+
+  /* Time at which the child will timeout.  Negative for no timeout.  */
+  kwsysProcessTime TimeoutTime;
+
+  /* Flag for whether the process was killed.  */
+  int Killed;
+
+  /* Flag for whether the timeout expired.  */
+  int TimeoutExpired;
+
+  /* Flag for whether the process has terminated.  */
+  int Terminated;
+
+  /* The number of pipes still open during execution and while waiting
+     for pipes to close after process termination.  */
+  int PipesLeft;
+
+  /* Buffer for error messages.  */
+  char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1];
+
+  /* Description for the ExitException.  */
+  char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1];
+
+  /* Windows process information data.  */
+  PROCESS_INFORMATION* ProcessInformation;
+
+  /* Data and process termination events for which to wait.  */
+  PHANDLE ProcessEvents;
+  int ProcessEventsLength;
+
+  /* Real working directory of our own process.  */
+  DWORD RealWorkingDirectoryLength;
+  wchar_t* RealWorkingDirectory;
+
+  /* Own handles for the child's ends of the pipes in the parent process.
+     Used temporarily during process creation.  */
+  HANDLE PipeChildStd[3];
+};
+
+/*--------------------------------------------------------------------------*/
+kwsysProcess* kwsysProcess_New(void)
+{
+  int i;
+
+  /* Process control structure.  */
+  kwsysProcess* cp;
+
+  /* Windows version number data.  */
+  OSVERSIONINFO osv;
+
+  /* Initialize list of processes before we get any farther.  It's especially
+     important that the console Ctrl handler be added BEFORE starting the
+     first process.  This prevents the risk of an orphaned process being
+     started by the main thread while the default Ctrl handler is in
+     progress.  */
+  if (!kwsysProcessesInitialize()) {
+    return 0;
+  }
+
+  /* Allocate a process control structure.  */
+  cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
+  if (!cp) {
+    /* Could not allocate memory for the control structure.  */
+    return 0;
+  }
+  ZeroMemory(cp, sizeof(*cp));
+
+  /* Share stdin with the parent process by default.  */
+  cp->PipeSharedSTDIN = 1;
+
+  /* Set initial status.  */
+  cp->State = kwsysProcess_State_Starting;
+
+  /* Choose a method of running the child based on version of
+     windows.  */
+  ZeroMemory(&osv, sizeof(osv));
+  osv.dwOSVersionInfoSize = sizeof(osv);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(push)
+#ifdef __INTEL_COMPILER
+#pragma warning(disable : 1478)
+#else
+#pragma warning(disable : 4996)
+#endif
+#endif
+  GetVersionEx(&osv);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(pop)
+#endif
+  if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+    /* Win9x no longer supported.  */
+    kwsysProcess_Delete(cp);
+    return 0;
+  }
+
+  /* Initially no thread owns the mutex.  Initialize semaphore to 1.  */
+  if (!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0))) {
+    kwsysProcess_Delete(cp);
+    return 0;
+  }
+
+  /* Initially no data are available.  Initialize semaphore to 0.  */
+  if (!(cp->Full = CreateSemaphore(0, 0, 1, 0))) {
+    kwsysProcess_Delete(cp);
+    return 0;
+  }
+
+  /* Create the thread to read each pipe.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    DWORD dummy = 0;
+
+    /* Assign the thread its index.  */
+    cp->Pipe[i].Index = i;
+
+    /* Give the thread a pointer back to the kwsysProcess instance.  */
+    cp->Pipe[i].Process = cp;
+
+    /* No process is yet running.  Initialize semaphore to 0.  */
+    if (!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0))) {
+      kwsysProcess_Delete(cp);
+      return 0;
+    }
+
+    /* The pipe is not yet reset.  Initialize semaphore to 0.  */
+    if (!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0))) {
+      kwsysProcess_Delete(cp);
+      return 0;
+    }
+
+    /* The thread's buffer is initially empty.  Initialize semaphore to 1.  */
+    if (!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0))) {
+      kwsysProcess_Delete(cp);
+      return 0;
+    }
+
+    /* Create the reading thread.  It will block immediately.  The
+       thread will not make deeply nested calls, so we need only a
+       small stack.  */
+    if (!(cp->Pipe[i].Reader.Thread = CreateThread(
+            0, 1024, kwsysProcessPipeThreadRead, &cp->Pipe[i], 0, &dummy))) {
+      kwsysProcess_Delete(cp);
+      return 0;
+    }
+
+    /* No process is yet running.  Initialize semaphore to 0.  */
+    if (!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0))) {
+      kwsysProcess_Delete(cp);
+      return 0;
+    }
+
+    /* The pipe is not yet reset.  Initialize semaphore to 0.  */
+    if (!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0))) {
+      kwsysProcess_Delete(cp);
+      return 0;
+    }
+
+    /* The waker should not wake immediately.  Initialize semaphore to 0.  */
+    if (!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0))) {
+      kwsysProcess_Delete(cp);
+      return 0;
+    }
+
+    /* Create the waking thread.  It will block immediately.  The
+       thread will not make deeply nested calls, so we need only a
+       small stack.  */
+    if (!(cp->Pipe[i].Waker.Thread = CreateThread(
+            0, 1024, kwsysProcessPipeThreadWake, &cp->Pipe[i], 0, &dummy))) {
+      kwsysProcess_Delete(cp);
+      return 0;
+    }
+  }
+  for (i = 0; i < 3; ++i) {
+    cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
+  }
+
+  return cp;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Delete(kwsysProcess* cp)
+{
+  int i;
+
+  /* Make sure we have an instance.  */
+  if (!cp) {
+    return;
+  }
+
+  /* If the process is executing, wait for it to finish.  */
+  if (cp->State == kwsysProcess_State_Executing) {
+    if (cp->Detached) {
+      kwsysProcess_Disown(cp);
+    } else {
+      kwsysProcess_WaitForExit(cp, 0);
+    }
+  }
+
+  /* We are deleting the kwsysProcess instance.  */
+  cp->Deleting = 1;
+
+  /* Terminate each of the threads.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    /* Terminate this reading thread.  */
+    if (cp->Pipe[i].Reader.Thread) {
+      /* Signal the thread we are ready for it.  It will terminate
+         immediately since Deleting is set.  */
+      ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
+
+      /* Wait for the thread to exit.  */
+      WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE);
+
+      /* Close the handle to the thread. */
+      kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread);
+    }
+
+    /* Terminate this waking thread.  */
+    if (cp->Pipe[i].Waker.Thread) {
+      /* Signal the thread we are ready for it.  It will terminate
+         immediately since Deleting is set.  */
+      ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
+
+      /* Wait for the thread to exit.  */
+      WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE);
+
+      /* Close the handle to the thread. */
+      kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread);
+    }
+
+    /* Cleanup the pipe's semaphores.  */
+    kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Ready);
+    kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Go);
+    kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Reset);
+    kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Ready);
+    kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Go);
+    kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Reset);
+  }
+
+  /* Close the shared semaphores.  */
+  kwsysProcessCleanupHandle(&cp->SharedIndexMutex);
+  kwsysProcessCleanupHandle(&cp->Full);
+
+  /* Free memory.  */
+  kwsysProcess_SetCommand(cp, 0);
+  kwsysProcess_SetWorkingDirectory(cp, 0);
+  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
+  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
+  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
+  if (cp->CommandExitCodes) {
+    free(cp->CommandExitCodes);
+  }
+  free(cp);
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
+{
+  int i;
+  if (!cp) {
+    return 0;
+  }
+  for (i = 0; i < cp->NumberOfCommands; ++i) {
+    free(cp->Commands[i]);
+  }
+  cp->NumberOfCommands = 0;
+  if (cp->Commands) {
+    free(cp->Commands);
+    cp->Commands = 0;
+  }
+  if (command) {
+    return kwsysProcess_AddCommand(cp, command);
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
+{
+  int newNumberOfCommands;
+  wchar_t** newCommands;
+
+  /* Make sure we have a command to add.  */
+  if (!cp || !command || !*command) {
+    return 0;
+  }
+
+  /* Allocate a new array for command pointers.  */
+  newNumberOfCommands = cp->NumberOfCommands + 1;
+  if (!(newCommands =
+          (wchar_t**)malloc(sizeof(wchar_t*) * newNumberOfCommands))) {
+    /* Out of memory.  */
+    return 0;
+  }
+
+  /* Copy any existing commands into the new array.  */
+  {
+    int i;
+    for (i = 0; i < cp->NumberOfCommands; ++i) {
+      newCommands[i] = cp->Commands[i];
+    }
+  }
+
+  if (cp->Verbatim) {
+    /* Copy the verbatim command line into the buffer.  */
+    newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(*command);
+  } else {
+    /* Encode the arguments so CommandLineToArgvW can decode
+       them from the command line string in the child.  */
+    char buffer[32768]; /* CreateProcess max command-line length.  */
+    char* end = buffer + sizeof(buffer);
+    char* out = buffer;
+    char const* const* a;
+    for (a = command; *a; ++a) {
+      int quote = !**a; /* Quote the empty string.  */
+      int slashes = 0;
+      char const* c;
+      if (a != command && out != end) {
+        *out++ = ' ';
+      }
+      for (c = *a; !quote && *c; ++c) {
+        quote = (*c == ' ' || *c == '\t');
+      }
+      if (quote && out != end) {
+        *out++ = '"';
+      }
+      for (c = *a; *c; ++c) {
+        if (*c == '\\') {
+          ++slashes;
+        } else {
+          if (*c == '"') {
+            // Add n+1 backslashes to total 2n+1 before internal '"'.
+            while (slashes-- >= 0 && out != end) {
+              *out++ = '\\';
+            }
+          }
+          slashes = 0;
+        }
+        if (out != end) {
+          *out++ = *c;
+        }
+      }
+      if (quote) {
+        // Add n backslashes to total 2n before ending '"'.
+        while (slashes-- > 0 && out != end) {
+          *out++ = '\\';
+        }
+        if (out != end) {
+          *out++ = '"';
+        }
+      }
+    }
+    if (out != end) {
+      *out = '\0';
+      newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(buffer);
+    } else {
+      newCommands[cp->NumberOfCommands] = 0;
+    }
+  }
+  if (!newCommands[cp->NumberOfCommands]) {
+    /* Out of memory or command line too long.  */
+    free(newCommands);
+    return 0;
+  }
+
+  /* Save the new array of commands.  */
+  free(cp->Commands);
+  cp->Commands = newCommands;
+  cp->NumberOfCommands = newNumberOfCommands;
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
+{
+  if (!cp) {
+    return;
+  }
+  cp->Timeout = timeout;
+  if (cp->Timeout < 0) {
+    cp->Timeout = 0;
+  }
+  // Force recomputation of TimeoutTime.
+  cp->TimeoutTime.QuadPart = -1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
+{
+  if (!cp) {
+    return 0;
+  }
+  if (cp->WorkingDirectory) {
+    free(cp->WorkingDirectory);
+    cp->WorkingDirectory = 0;
+  }
+  if (dir && dir[0]) {
+    wchar_t* wdir = kwsysEncoding_DupToWide(dir);
+    /* We must convert the working directory to a full path.  */
+    DWORD length = GetFullPathNameW(wdir, 0, 0, 0);
+    if (length > 0) {
+      wchar_t* work_dir = malloc(length * sizeof(wchar_t));
+      if (!work_dir) {
+        free(wdir);
+        return 0;
+      }
+      if (!GetFullPathNameW(wdir, length, work_dir, 0)) {
+        free(work_dir);
+        free(wdir);
+        return 0;
+      }
+      cp->WorkingDirectory = work_dir;
+    }
+    free(wdir);
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
+{
+  char** pfile;
+  if (!cp) {
+    return 0;
+  }
+  switch (pipe) {
+    case kwsysProcess_Pipe_STDIN:
+      pfile = &cp->PipeFileSTDIN;
+      break;
+    case kwsysProcess_Pipe_STDOUT:
+      pfile = &cp->PipeFileSTDOUT;
+      break;
+    case kwsysProcess_Pipe_STDERR:
+      pfile = &cp->PipeFileSTDERR;
+      break;
+    default:
+      return 0;
+  }
+  if (*pfile) {
+    free(*pfile);
+    *pfile = 0;
+  }
+  if (file) {
+    *pfile = (char*)malloc(strlen(file) + 1);
+    if (!*pfile) {
+      return 0;
+    }
+    strcpy(*pfile, file);
+  }
+
+  /* If we are redirecting the pipe, do not share it or use a native
+     pipe.  */
+  if (*pfile) {
+    kwsysProcess_SetPipeNative(cp, pipe, 0);
+    kwsysProcess_SetPipeShared(cp, pipe, 0);
+  }
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
+{
+  if (!cp) {
+    return;
+  }
+
+  switch (pipe) {
+    case kwsysProcess_Pipe_STDIN:
+      cp->PipeSharedSTDIN = shared ? 1 : 0;
+      break;
+    case kwsysProcess_Pipe_STDOUT:
+      cp->PipeSharedSTDOUT = shared ? 1 : 0;
+      break;
+    case kwsysProcess_Pipe_STDERR:
+      cp->PipeSharedSTDERR = shared ? 1 : 0;
+      break;
+    default:
+      return;
+  }
+
+  /* If we are sharing the pipe, do not redirect it to a file or use a
+     native pipe.  */
+  if (shared) {
+    kwsysProcess_SetPipeFile(cp, pipe, 0);
+    kwsysProcess_SetPipeNative(cp, pipe, 0);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, HANDLE p[2])
+{
+  HANDLE* pPipeNative = 0;
+
+  if (!cp) {
+    return;
+  }
+
+  switch (pipe) {
+    case kwsysProcess_Pipe_STDIN:
+      pPipeNative = cp->PipeNativeSTDIN;
+      break;
+    case kwsysProcess_Pipe_STDOUT:
+      pPipeNative = cp->PipeNativeSTDOUT;
+      break;
+    case kwsysProcess_Pipe_STDERR:
+      pPipeNative = cp->PipeNativeSTDERR;
+      break;
+    default:
+      return;
+  }
+
+  /* Copy the native pipe handles provided.  */
+  if (p) {
+    pPipeNative[0] = p[0];
+    pPipeNative[1] = p[1];
+  } else {
+    pPipeNative[0] = 0;
+    pPipeNative[1] = 0;
+  }
+
+  /* If we are using a native pipe, do not share it or redirect it to
+     a file.  */
+  if (p) {
+    kwsysProcess_SetPipeFile(cp, pipe, 0);
+    kwsysProcess_SetPipeShared(cp, pipe, 0);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
+{
+  if (!cp) {
+    return 0;
+  }
+
+  switch (optionId) {
+    case kwsysProcess_Option_Detach:
+      return cp->OptionDetach;
+    case kwsysProcess_Option_HideWindow:
+      return cp->HideWindow;
+    case kwsysProcess_Option_MergeOutput:
+      return cp->MergeOutput;
+    case kwsysProcess_Option_Verbatim:
+      return cp->Verbatim;
+    case kwsysProcess_Option_CreateProcessGroup:
+      return cp->CreateProcessGroup;
+    default:
+      return 0;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
+{
+  if (!cp) {
+    return;
+  }
+
+  switch (optionId) {
+    case kwsysProcess_Option_Detach:
+      cp->OptionDetach = value;
+      break;
+    case kwsysProcess_Option_HideWindow:
+      cp->HideWindow = value;
+      break;
+    case kwsysProcess_Option_MergeOutput:
+      cp->MergeOutput = value;
+      break;
+    case kwsysProcess_Option_Verbatim:
+      cp->Verbatim = value;
+      break;
+    case kwsysProcess_Option_CreateProcessGroup:
+      cp->CreateProcessGroup = value;
+      break;
+    default:
+      break;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetState(kwsysProcess* cp)
+{
+  return cp ? cp->State : kwsysProcess_State_Error;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitException(kwsysProcess* cp)
+{
+  return cp ? cp->ExitException : kwsysProcess_Exception_Other;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitValue(kwsysProcess* cp)
+{
+  return cp ? cp->ExitValue : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitCode(kwsysProcess* cp)
+{
+  return cp ? cp->ExitCode : 0;
+}
+
+/*--------------------------------------------------------------------------*/
+const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
+{
+  if (!cp) {
+    return "Process management structure could not be allocated";
+  } else if (cp->State == kwsysProcess_State_Error) {
+    return cp->ErrorMessage;
+  }
+  return "Success";
+}
+
+/*--------------------------------------------------------------------------*/
+const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
+{
+  if (!cp) {
+    return "GetExceptionString called with NULL process management structure";
+  } else if (cp->State == kwsysProcess_State_Exception) {
+    return cp->ExitExceptionString;
+  }
+  return "No exception";
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Execute(kwsysProcess* cp)
+{
+  int i;
+
+  /* Do not execute a second time.  */
+  if (!cp || cp->State == kwsysProcess_State_Executing) {
+    return;
+  }
+
+  /* Make sure we have something to run.  */
+  if (cp->NumberOfCommands < 1) {
+    strcpy(cp->ErrorMessage, "No command");
+    cp->State = kwsysProcess_State_Error;
+    return;
+  }
+
+  /* Initialize the control structure for a new process.  */
+  if (!kwsysProcessInitialize(cp)) {
+    strcpy(cp->ErrorMessage, "Out of memory");
+    cp->State = kwsysProcess_State_Error;
+    return;
+  }
+
+  /* Save the real working directory of this process and change to
+     the working directory for the child processes.  This is needed
+     to make pipe file paths evaluate correctly.  */
+  if (cp->WorkingDirectory) {
+    if (!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength,
+                              cp->RealWorkingDirectory)) {
+      kwsysProcessCleanup(cp, GetLastError());
+      return;
+    }
+    SetCurrentDirectoryW(cp->WorkingDirectory);
+  }
+
+  /* Setup the stdin pipe for the first process.  */
+  if (cp->PipeFileSTDIN) {
+    /* Create a handle to read a file for stdin.  */
+    wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN);
+    DWORD error;
+    cp->PipeChildStd[0] =
+      CreateFileW(wstdin, GENERIC_READ | GENERIC_WRITE,
+                  FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
+    error = GetLastError(); /* Check now in case free changes this.  */
+    free(wstdin);
+    if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) {
+      kwsysProcessCleanup(cp, error);
+      return;
+    }
+  } else if (cp->PipeSharedSTDIN) {
+    /* Share this process's stdin with the child.  */
+    kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]);
+  } else if (cp->PipeNativeSTDIN[0]) {
+    /* Use the provided native pipe.  */
+    kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]);
+  } else {
+    /* Explicitly give the child no stdin.  */
+    cp->PipeChildStd[0] = INVALID_HANDLE_VALUE;
+  }
+
+  /* Create the output pipe for the last process.
+     We always create this so the pipe thread can run even if we
+     do not end up giving the write end to the child below.  */
+  if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read,
+                  &cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0)) {
+    kwsysProcessCleanup(cp, GetLastError());
+    return;
+  }
+
+  if (cp->PipeFileSTDOUT) {
+    /* Use a file for stdout.  */
+    DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
+                                                  cp->PipeFileSTDOUT);
+    if (error) {
+      kwsysProcessCleanup(cp, error);
+      return;
+    }
+  } else if (cp->PipeSharedSTDOUT) {
+    /* Use the parent stdout.  */
+    kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]);
+  } else if (cp->PipeNativeSTDOUT[1]) {
+    /* Use the given handle for stdout.  */
+    kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]);
+  } else {
+    /* Use our pipe for stdout.  Duplicate the handle since our waker
+       thread will use the original.  Do not make it inherited yet.  */
+    if (!DuplicateHandle(GetCurrentProcess(),
+                         cp->Pipe[KWSYSPE_PIPE_STDOUT].Write,
+                         GetCurrentProcess(), &cp->PipeChildStd[1], 0, FALSE,
+                         DUPLICATE_SAME_ACCESS)) {
+      kwsysProcessCleanup(cp, GetLastError());
+      return;
+    }
+  }
+
+  /* Create stderr pipe to be shared by all processes in the pipeline.
+     We always create this so the pipe thread can run even if we do not
+     end up giving the write end to the child below.  */
+  if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
+                  &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) {
+    kwsysProcessCleanup(cp, GetLastError());
+    return;
+  }
+
+  if (cp->PipeFileSTDERR) {
+    /* Use a file for stderr.  */
+    DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
+                                                  cp->PipeFileSTDERR);
+    if (error) {
+      kwsysProcessCleanup(cp, error);
+      return;
+    }
+  } else if (cp->PipeSharedSTDERR) {
+    /* Use the parent stderr.  */
+    kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]);
+  } else if (cp->PipeNativeSTDERR[1]) {
+    /* Use the given handle for stderr.  */
+    kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]);
+  } else {
+    /* Use our pipe for stderr.  Duplicate the handle since our waker
+       thread will use the original.  Do not make it inherited yet.  */
+    if (!DuplicateHandle(GetCurrentProcess(),
+                         cp->Pipe[KWSYSPE_PIPE_STDERR].Write,
+                         GetCurrentProcess(), &cp->PipeChildStd[2], 0, FALSE,
+                         DUPLICATE_SAME_ACCESS)) {
+      kwsysProcessCleanup(cp, GetLastError());
+      return;
+    }
+  }
+
+  /* Create the pipeline of processes.  */
+  {
+    /* Child startup control data.  */
+    kwsysProcessCreateInformation si;
+    HANDLE nextStdInput = cp->PipeChildStd[0];
+
+    /* Initialize startup info data.  */
+    ZeroMemory(&si, sizeof(si));
+    si.StartupInfo.cb = sizeof(si.StartupInfo);
+
+    /* Decide whether a child window should be shown.  */
+    si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
+    si.StartupInfo.wShowWindow =
+      (unsigned short)(cp->HideWindow ? SW_HIDE : SW_SHOWDEFAULT);
+
+    /* Connect the child's output pipes to the threads.  */
+    si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+    for (i = 0; i < cp->NumberOfCommands; ++i) {
+      /* Setup the process's pipes.  */
+      si.hStdInput = nextStdInput;
+      if (i == cp->NumberOfCommands - 1) {
+        /* The last child gets the overall stdout.  */
+        nextStdInput = INVALID_HANDLE_VALUE;
+        si.hStdOutput = cp->PipeChildStd[1];
+      } else {
+        /* Create a pipe to sit between the children.  */
+        HANDLE p[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
+        if (!CreatePipe(&p[0], &p[1], 0, 0)) {
+          DWORD error = GetLastError();
+          if (nextStdInput != cp->PipeChildStd[0]) {
+            kwsysProcessCleanupHandle(&nextStdInput);
+          }
+          kwsysProcessCleanup(cp, error);
+          return;
+        }
+        nextStdInput = p[0];
+        si.hStdOutput = p[1];
+      }
+      si.hStdError =
+        cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2];
+
+      {
+        DWORD error = kwsysProcessCreate(cp, i, &si);
+
+        /* Close our copies of pipes used between children.  */
+        if (si.hStdInput != cp->PipeChildStd[0]) {
+          kwsysProcessCleanupHandle(&si.hStdInput);
+        }
+        if (si.hStdOutput != cp->PipeChildStd[1]) {
+          kwsysProcessCleanupHandle(&si.hStdOutput);
+        }
+        if (si.hStdError != cp->PipeChildStd[2] && !cp->MergeOutput) {
+          kwsysProcessCleanupHandle(&si.hStdError);
+        }
+        if (!error) {
+          cp->ProcessEvents[i + 1] = cp->ProcessInformation[i].hProcess;
+        } else {
+          if (nextStdInput != cp->PipeChildStd[0]) {
+            kwsysProcessCleanupHandle(&nextStdInput);
+          }
+          kwsysProcessCleanup(cp, error);
+          return;
+        }
+      }
+    }
+  }
+
+  /* The parent process does not need the child's pipe ends.  */
+  for (i = 0; i < 3; ++i) {
+    kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
+  }
+
+  /* Restore the working directory.  */
+  if (cp->RealWorkingDirectory) {
+    SetCurrentDirectoryW(cp->RealWorkingDirectory);
+    free(cp->RealWorkingDirectory);
+    cp->RealWorkingDirectory = 0;
+  }
+
+  /* The timeout period starts now.  */
+  cp->StartTime = kwsysProcessTimeGetCurrent();
+  cp->TimeoutTime = kwsysProcessTimeFromDouble(-1);
+
+  /* All processes in the pipeline have been started in suspended
+     mode.  Resume them all now.  */
+  for (i = 0; i < cp->NumberOfCommands; ++i) {
+    ResumeThread(cp->ProcessInformation[i].hThread);
+  }
+
+  /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */
+  /* Tell the pipe threads that a process has started.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
+    ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
+  }
+
+  /* We don't care about the children's main threads.  */
+  for (i = 0; i < cp->NumberOfCommands; ++i) {
+    kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
+  }
+
+  /* No pipe has reported data.  */
+  cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
+  cp->PipesLeft = KWSYSPE_PIPE_COUNT;
+
+  /* The process has now started.  */
+  cp->State = kwsysProcess_State_Executing;
+  cp->Detached = cp->OptionDetach;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Disown(kwsysProcess* cp)
+{
+  int i;
+
+  /* Make sure we are executing a detached process.  */
+  if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
+      cp->TimeoutExpired || cp->Killed || cp->Terminated) {
+    return;
+  }
+
+  /* Disable the reading threads.  */
+  kwsysProcessDisablePipeThreads(cp);
+
+  /* Wait for all pipe threads to reset.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
+    WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
+  }
+
+  /* We will not wait for exit, so cleanup now.  */
+  kwsysProcessCleanup(cp, 0);
+
+  /* The process has been disowned.  */
+  cp->State = kwsysProcess_State_Disowned;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
+                             double* userTimeout)
+{
+  kwsysProcessTime userStartTime;
+  kwsysProcessTime timeoutLength;
+  kwsysProcessTime timeoutTime;
+  DWORD timeout;
+  int user;
+  int done = 0;
+  int expired = 0;
+  int pipeId = kwsysProcess_Pipe_None;
+  DWORD w;
+
+  /* Make sure we are executing a process.  */
+  if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
+      cp->TimeoutExpired) {
+    return kwsysProcess_Pipe_None;
+  }
+
+  /* Record the time at which user timeout period starts.  */
+  userStartTime = kwsysProcessTimeGetCurrent();
+
+  /* Calculate the time at which a timeout will expire, and whether it
+     is the user or process timeout.  */
+  user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime);
+
+  /* Loop until we have a reason to return.  */
+  while (!done && cp->PipesLeft > 0) {
+    /* If we previously got data from a thread, let it know we are
+       done with the data.  */
+    if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
+      KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
+      ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
+      cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
+    }
+
+    /* Setup a timeout if required.  */
+    if (kwsysProcessGetTimeoutLeft(&timeoutTime, user ? userTimeout : 0,
+                                   &timeoutLength)) {
+      /* Timeout has already expired.  */
+      expired = 1;
+      break;
+    }
+    if (timeoutTime.QuadPart < 0) {
+      timeout = INFINITE;
+    } else {
+      timeout = kwsysProcessTimeToDWORD(timeoutLength);
+    }
+
+    /* Wait for a pipe's thread to signal or a process to terminate.  */
+    w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents, 0,
+                               timeout);
+    if (w == WAIT_TIMEOUT) {
+      /* Timeout has expired.  */
+      expired = 1;
+      done = 1;
+    } else if (w == WAIT_OBJECT_0) {
+      /* Save the index of the reporting thread and release the mutex.
+         The thread will block until we signal its Empty mutex.  */
+      cp->CurrentIndex = cp->SharedIndex;
+      ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
+
+      /* Data are available or a pipe closed.  */
+      if (cp->Pipe[cp->CurrentIndex].Closed) {
+        /* The pipe closed at the write end.  Close the read end and
+           inform the wakeup thread it is done with this process.  */
+        kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read);
+        ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Waker.Go, 1, 0);
+        KWSYSPE_DEBUG((stderr, "wakeup %d\n", cp->CurrentIndex));
+        --cp->PipesLeft;
+      } else if (data && length) {
+        /* Report this data.  */
+        *data = cp->Pipe[cp->CurrentIndex].DataBuffer;
+        *length = cp->Pipe[cp->CurrentIndex].DataLength;
+        switch (cp->CurrentIndex) {
+          case KWSYSPE_PIPE_STDOUT:
+            pipeId = kwsysProcess_Pipe_STDOUT;
+            break;
+          case KWSYSPE_PIPE_STDERR:
+            pipeId = kwsysProcess_Pipe_STDERR;
+            break;
+        }
+        done = 1;
+      }
+    } else {
+      /* A process has terminated.  */
+      kwsysProcessDestroy(cp, w - WAIT_OBJECT_0);
+    }
+  }
+
+  /* Update the user timeout.  */
+  if (userTimeout) {
+    kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
+    kwsysProcessTime difference =
+      kwsysProcessTimeSubtract(userEndTime, userStartTime);
+    double d = kwsysProcessTimeToDouble(difference);
+    *userTimeout -= d;
+    if (*userTimeout < 0) {
+      *userTimeout = 0;
+    }
+  }
+
+  /* Check what happened.  */
+  if (pipeId) {
+    /* Data are ready on a pipe.  */
+    return pipeId;
+  } else if (expired) {
+    /* A timeout has expired.  */
+    if (user) {
+      /* The user timeout has expired.  It has no time left.  */
+      return kwsysProcess_Pipe_Timeout;
+    } else {
+      /* The process timeout has expired.  Kill the child now.  */
+      KWSYSPE_DEBUG((stderr, "killing child because timeout expired\n"));
+      kwsysProcess_Kill(cp);
+      cp->TimeoutExpired = 1;
+      cp->Killed = 0;
+      return kwsysProcess_Pipe_None;
+    }
+  } else {
+    /* The children have terminated and no more data are available.  */
+    return kwsysProcess_Pipe_None;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
+{
+  int i;
+  int pipe;
+
+  /* Make sure we are executing a process.  */
+  if (!cp || cp->State != kwsysProcess_State_Executing) {
+    return 1;
+  }
+
+  /* Wait for the process to terminate.  Ignore all data.  */
+  while ((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) {
+    if (pipe == kwsysProcess_Pipe_Timeout) {
+      /* The user timeout has expired.  */
+      return 0;
+    }
+  }
+
+  KWSYSPE_DEBUG((stderr, "no more data\n"));
+
+  /* When the last pipe closes in WaitForData, the loop terminates
+     without releasing the pipe's thread.  Release it now.  */
+  if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
+    KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
+    ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
+    cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
+  }
+
+  /* Wait for all pipe threads to reset.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    KWSYSPE_DEBUG((stderr, "waiting reader reset %d\n", i));
+    WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
+    KWSYSPE_DEBUG((stderr, "waiting waker reset %d\n", i));
+    WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
+  }
+
+  /* ---- It is now safe again to call kwsysProcessCleanup. ----- */
+  /* Close all the pipes.  */
+  kwsysProcessCleanup(cp, 0);
+
+  /* Determine the outcome.  */
+  if (cp->Killed) {
+    /* We killed the child.  */
+    cp->State = kwsysProcess_State_Killed;
+  } else if (cp->TimeoutExpired) {
+    /* The timeout expired.  */
+    cp->State = kwsysProcess_State_Expired;
+  } else {
+    /* The children exited.  Report the outcome of the last process.  */
+    cp->ExitCode = cp->CommandExitCodes[cp->NumberOfCommands - 1];
+    if ((cp->ExitCode & 0xF0000000) == 0xC0000000) {
+      /* Child terminated due to exceptional behavior.  */
+      cp->State = kwsysProcess_State_Exception;
+      cp->ExitValue = 1;
+      kwsysProcessSetExitException(cp, cp->ExitCode);
+    } else {
+      /* Child exited without exception.  */
+      cp->State = kwsysProcess_State_Exited;
+      cp->ExitException = kwsysProcess_Exception_None;
+      cp->ExitValue = cp->ExitCode;
+    }
+  }
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Interrupt(kwsysProcess* cp)
+{
+  int i;
+  /* Make sure we are executing a process.  */
+  if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+      cp->Killed) {
+    KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n"));
+    return;
+  }
+
+  /* Skip actually interrupting the child if it has already terminated.  */
+  if (cp->Terminated) {
+    KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n"));
+    return;
+  }
+
+  /* Interrupt the children.  */
+  if (cp->CreateProcessGroup) {
+    if (cp->ProcessInformation) {
+      for (i = 0; i < cp->NumberOfCommands; ++i) {
+        /* Make sure the process handle isn't closed (e.g. from disowning). */
+        if (cp->ProcessInformation[i].hProcess) {
+          /* The user created a process group for this process.  The group ID
+             is the process ID for the original process in the group.  Note
+             that we have to use Ctrl+Break: Ctrl+C is not allowed for process
+             groups.  */
+          GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
+                                   cp->ProcessInformation[i].dwProcessId);
+        }
+      }
+    }
+  } else {
+    /* No process group was created.  Kill our own process group...  */
+    GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_Kill(kwsysProcess* cp)
+{
+  int i;
+  /* Make sure we are executing a process.  */
+  if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+      cp->Killed) {
+    KWSYSPE_DEBUG((stderr, "kill: child not executing\n"));
+    return;
+  }
+
+  /* Disable the reading threads.  */
+  KWSYSPE_DEBUG((stderr, "kill: disabling pipe threads\n"));
+  kwsysProcessDisablePipeThreads(cp);
+
+  /* Skip actually killing the child if it has already terminated.  */
+  if (cp->Terminated) {
+    KWSYSPE_DEBUG((stderr, "kill: child already terminated\n"));
+    return;
+  }
+
+  /* Kill the children.  */
+  cp->Killed = 1;
+  for (i = 0; i < cp->NumberOfCommands; ++i) {
+    kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId);
+    /* Remove from global list of processes and close handles.  */
+    kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
+    kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
+    kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
+  }
+
+  /* We are killing the children and ignoring all data.  Do not wait
+     for them to exit.  */
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+  Function executed for each pipe's thread.  Argument is a pointer to
+  the kwsysProcessPipeData instance for this thread.
+*/
+DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd)
+{
+  kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd;
+  kwsysProcess* cp = td->Process;
+
+  /* Wait for a process to be ready.  */
+  while ((WaitForSingleObject(td->Reader.Ready, INFINITE), !cp->Deleting)) {
+    /* Read output from the process for this thread's pipe.  */
+    kwsysProcessPipeThreadReadPipe(cp, td);
+
+    /* Signal the main thread we have reset for a new process.  */
+    ReleaseSemaphore(td->Reader.Reset, 1, 0);
+  }
+  return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+  Function called in each pipe's thread to handle data for one
+  execution of a subprocess.
+*/
+void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td)
+{
+  /* Wait for space in the thread's buffer. */
+  while ((KWSYSPE_DEBUG((stderr, "wait for read %d\n", td->Index)),
+          WaitForSingleObject(td->Reader.Go, INFINITE), !td->Closed)) {
+    KWSYSPE_DEBUG((stderr, "reading %d\n", td->Index));
+
+    /* Read data from the pipe.  This may block until data are available.  */
+    if (!ReadFile(td->Read, td->DataBuffer, KWSYSPE_PIPE_BUFFER_SIZE,
+                  &td->DataLength, 0)) {
+      if (GetLastError() != ERROR_BROKEN_PIPE) {
+        /* UNEXPECTED failure to read the pipe.  */
+      }
+
+      /* The pipe closed.  There are no more data to read.  */
+      td->Closed = 1;
+      KWSYSPE_DEBUG((stderr, "read closed %d\n", td->Index));
+    }
+
+    KWSYSPE_DEBUG((stderr, "read %d\n", td->Index));
+
+    /* Wait for our turn to be handled by the main thread.  */
+    WaitForSingleObject(cp->SharedIndexMutex, INFINITE);
+
+    KWSYSPE_DEBUG((stderr, "reporting read %d\n", td->Index));
+
+    /* Tell the main thread we have something to report.  */
+    cp->SharedIndex = td->Index;
+    ReleaseSemaphore(cp->Full, 1, 0);
+  }
+
+  /* We were signalled to exit with our buffer empty.  Reset the
+     mutex for a new process.  */
+  KWSYSPE_DEBUG((stderr, "self releasing reader %d\n", td->Index));
+  ReleaseSemaphore(td->Reader.Go, 1, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+  Function executed for each pipe's thread.  Argument is a pointer to
+  the kwsysProcessPipeData instance for this thread.
+*/
+DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd)
+{
+  kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd;
+  kwsysProcess* cp = td->Process;
+
+  /* Wait for a process to be ready.  */
+  while ((WaitForSingleObject(td->Waker.Ready, INFINITE), !cp->Deleting)) {
+    /* Wait for a possible wakeup.  */
+    kwsysProcessPipeThreadWakePipe(cp, td);
+
+    /* Signal the main thread we have reset for a new process.  */
+    ReleaseSemaphore(td->Waker.Reset, 1, 0);
+  }
+  return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+  Function called in each pipe's thread to handle reading thread
+  wakeup for one execution of a subprocess.
+*/
+void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, kwsysProcessPipeData* td)
+{
+  (void)cp;
+
+  /* Wait for a possible wake command. */
+  KWSYSPE_DEBUG((stderr, "wait for wake %d\n", td->Index));
+  WaitForSingleObject(td->Waker.Go, INFINITE);
+  KWSYSPE_DEBUG((stderr, "waking %d\n", td->Index));
+
+  /* If the pipe is not closed, we need to wake up the reading thread.  */
+  if (!td->Closed) {
+    DWORD dummy;
+    KWSYSPE_DEBUG((stderr, "waker %d writing byte\n", td->Index));
+    WriteFile(td->Write, "", 1, &dummy, 0);
+    KWSYSPE_DEBUG((stderr, "waker %d wrote byte\n", td->Index));
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Initialize a process control structure for kwsysProcess_Execute.  */
+int kwsysProcessInitialize(kwsysProcess* cp)
+{
+  /* Reset internal status flags.  */
+  cp->TimeoutExpired = 0;
+  cp->Terminated = 0;
+  cp->Killed = 0;
+  cp->ExitException = kwsysProcess_Exception_None;
+  cp->ExitCode = 1;
+  cp->ExitValue = 1;
+
+  /* Reset error data.  */
+  cp->ErrorMessage[0] = 0;
+  strcpy(cp->ExitExceptionString, "No exception");
+
+  /* Allocate process information for each process.  */
+  cp->ProcessInformation = (PROCESS_INFORMATION*)malloc(
+    sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
+  if (!cp->ProcessInformation) {
+    return 0;
+  }
+  ZeroMemory(cp->ProcessInformation,
+             sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
+  if (cp->CommandExitCodes) {
+    free(cp->CommandExitCodes);
+  }
+  cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD) * cp->NumberOfCommands);
+  if (!cp->CommandExitCodes) {
+    return 0;
+  }
+  ZeroMemory(cp->CommandExitCodes, sizeof(DWORD) * cp->NumberOfCommands);
+
+  /* Allocate event wait array.  The first event is cp->Full, the rest
+     are the process termination events.  */
+  cp->ProcessEvents =
+    (PHANDLE)malloc(sizeof(HANDLE) * (cp->NumberOfCommands + 1));
+  if (!cp->ProcessEvents) {
+    return 0;
+  }
+  ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands + 1));
+  cp->ProcessEvents[0] = cp->Full;
+  cp->ProcessEventsLength = cp->NumberOfCommands + 1;
+
+  /* Allocate space to save the real working directory of this process.  */
+  if (cp->WorkingDirectory) {
+    cp->RealWorkingDirectoryLength = GetCurrentDirectoryW(0, 0);
+    if (cp->RealWorkingDirectoryLength > 0) {
+      cp->RealWorkingDirectory =
+        malloc(cp->RealWorkingDirectoryLength * sizeof(wchar_t));
+      if (!cp->RealWorkingDirectory) {
+        return 0;
+      }
+    }
+  }
+  {
+    int i;
+    for (i = 0; i < 3; ++i) {
+      cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
+    }
+  }
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
+{
+  DWORD flags;
+
+  /* Check whether the handle is valid for this process.  */
+  if (in != INVALID_HANDLE_VALUE && GetHandleInformation(in, &flags)) {
+    /* Use the handle as-is if it is already inherited.  */
+    if (flags & HANDLE_FLAG_INHERIT) {
+      *out = in;
+      return ERROR_SUCCESS;
+    }
+
+    /* Create an inherited copy of this handle.  */
+    if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out, 0,
+                        TRUE, DUPLICATE_SAME_ACCESS)) {
+      return ERROR_SUCCESS;
+    } else {
+      return GetLastError();
+    }
+  } else {
+    /* The given handle is not valid for this process.  Some child
+       processes may break if they do not have a valid standard handle,
+       so open NUL to give to the child.  */
+    SECURITY_ATTRIBUTES sa;
+    ZeroMemory(&sa, sizeof(sa));
+    sa.nLength = (DWORD)sizeof(sa);
+    sa.bInheritHandle = 1;
+    *out = CreateFileW(
+      L"NUL",
+      (isStdIn ? GENERIC_READ : (GENERIC_WRITE | FILE_READ_ATTRIBUTES)),
+      FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0);
+    return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError();
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
+                         kwsysProcessCreateInformation* si)
+{
+  DWORD creationFlags;
+  DWORD error = ERROR_SUCCESS;
+
+  /* Check if we are currently exiting.  */
+  if (!kwsysTryEnterCreateProcessSection()) {
+    /* The Ctrl handler is currently working on exiting our process.  Rather
+    than return an error code, which could cause incorrect conclusions to be
+    reached by the caller, we simply hang.  (For example, a CMake try_run
+    configure step might cause the project to configure wrong.)  */
+    Sleep(INFINITE);
+  }
+
+  /* Create the child in a suspended state so we can wait until all
+     children have been created before running any one.  */
+  creationFlags = CREATE_SUSPENDED;
+  if (cp->CreateProcessGroup) {
+    creationFlags |= CREATE_NEW_PROCESS_GROUP;
+  }
+
+  /* Create inherited copies of the handles.  */
+  (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput,
+                                         si->hStdInput, 1)) ||
+    (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput,
+                                           si->hStdOutput, 0)) ||
+    (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError,
+                                           si->hStdError, 0)) ||
+    /* Create the process.  */
+    (!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0, 0,
+                     &si->StartupInfo, &cp->ProcessInformation[index]) &&
+     (error = GetLastError()));
+
+  /* Close the inherited copies of the handles. */
+  if (si->StartupInfo.hStdInput != si->hStdInput) {
+    kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
+  }
+  if (si->StartupInfo.hStdOutput != si->hStdOutput) {
+    kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
+  }
+  if (si->StartupInfo.hStdError != si->hStdError) {
+    kwsysProcessCleanupHandle(&si->StartupInfo.hStdError);
+  }
+
+  /* Add the process to the global list of processes. */
+  if (!error &&
+      !kwsysProcessesAdd(cp->ProcessInformation[index].hProcess,
+                         cp->ProcessInformation[index].dwProcessId,
+                         cp->CreateProcessGroup)) {
+    /* This failed for some reason.  Kill the suspended process. */
+    TerminateProcess(cp->ProcessInformation[index].hProcess, 1);
+    /* And clean up... */
+    kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
+    kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread);
+    strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed");
+    error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason.  */
+  }
+
+  /* If the console Ctrl handler is waiting for us, this will release it... */
+  kwsysLeaveCreateProcessSection();
+  return error;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessDestroy(kwsysProcess* cp, int event)
+{
+  int i;
+  int index;
+
+  /* Find the process index for the termination event.  */
+  for (index = 0; index < cp->NumberOfCommands; ++index) {
+    if (cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event]) {
+      break;
+    }
+  }
+
+  /* Check the exit code of the process.  */
+  GetExitCodeProcess(cp->ProcessInformation[index].hProcess,
+                     &cp->CommandExitCodes[index]);
+
+  /* Remove from global list of processes.  */
+  kwsysProcessesRemove(cp->ProcessInformation[index].hProcess);
+
+  /* Close the process handle for the terminated process.  */
+  kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
+
+  /* Remove the process from the available events.  */
+  cp->ProcessEventsLength -= 1;
+  for (i = event; i < cp->ProcessEventsLength; ++i) {
+    cp->ProcessEvents[i] = cp->ProcessEvents[i + 1];
+  }
+
+  /* Check if all processes have terminated.  */
+  if (cp->ProcessEventsLength == 1) {
+    cp->Terminated = 1;
+
+    /* Close our copies of the pipe write handles so the pipe threads
+       can detect end-of-data.  */
+    for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+      /* TODO: If the child created its own child (our grandchild)
+         which inherited a copy of the pipe write-end then the pipe
+         may not close and we will still need the waker write pipe.
+         However we still want to be able to detect end-of-data in the
+         normal case.  The reader thread will have to switch to using
+         PeekNamedPipe to read the last bit of data from the pipe
+         without blocking.  This is equivalent to using a non-blocking
+         read on posix.  */
+      KWSYSPE_DEBUG((stderr, "closing wakeup write %d\n", i));
+      kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
+    }
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
+{
+  HANDLE fout;
+  wchar_t* wname;
+  DWORD error;
+  if (!name) {
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  /* Close the existing handle.  */
+  kwsysProcessCleanupHandle(phandle);
+
+  /* Create a handle to write a file for the pipe.  */
+  wname = kwsysEncoding_DupToWide(name);
+  fout =
+    CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
+  error = GetLastError();
+  free(wname);
+  if (fout == INVALID_HANDLE_VALUE) {
+    return error;
+  }
+
+  /* Assign the replacement handle.  */
+  *phandle = fout;
+  return ERROR_SUCCESS;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
+{
+  /* Close the existing handle.  */
+  kwsysProcessCleanupHandle(handle);
+  /* Store the new standard handle.  */
+  *handle = GetStdHandle(nStdHandle);
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle)
+{
+  /* Close the existing handle.  */
+  kwsysProcessCleanupHandle(handle);
+  /* Store the new given handle.  */
+  *handle = native;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Close the given handle if it is open.  Reset its value to 0.  */
+void kwsysProcessCleanupHandle(PHANDLE h)
+{
+  if (h && *h && *h != INVALID_HANDLE_VALUE &&
+      *h != GetStdHandle(STD_INPUT_HANDLE) &&
+      *h != GetStdHandle(STD_OUTPUT_HANDLE) &&
+      *h != GetStdHandle(STD_ERROR_HANDLE)) {
+    CloseHandle(*h);
+    *h = INVALID_HANDLE_VALUE;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Close all handles created by kwsysProcess_Execute.  */
+void kwsysProcessCleanup(kwsysProcess* cp, DWORD error)
+{
+  int i;
+  /* If this is an error case, report the error.  */
+  if (error) {
+    /* Construct an error message if one has not been provided already.  */
+    if (cp->ErrorMessage[0] == 0) {
+      /* Format the error message.  */
+      wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE];
+      DWORD length = FormatMessageW(
+        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_msg,
+        KWSYSPE_PIPE_BUFFER_SIZE, 0);
+      if (length < 1) {
+        /* FormatMessage failed.  Use a default message.  */
+        _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
+                  "Process execution failed with error 0x%X.  "
+                  "FormatMessage failed with error 0x%X",
+                  error, GetLastError());
+      }
+      if (!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage,
+                               KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL)) {
+        /* WideCharToMultiByte failed.  Use a default message.  */
+        _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
+                  "Process execution failed with error 0x%X.  "
+                  "WideCharToMultiByte failed with error 0x%X",
+                  error, GetLastError());
+      }
+    }
+
+    /* Remove trailing period and newline, if any.  */
+    kwsysProcessCleanErrorMessage(cp);
+
+    /* Set the error state.  */
+    cp->State = kwsysProcess_State_Error;
+
+    /* Cleanup any processes already started in a suspended state.  */
+    if (cp->ProcessInformation) {
+      for (i = 0; i < cp->NumberOfCommands; ++i) {
+        if (cp->ProcessInformation[i].hProcess) {
+          TerminateProcess(cp->ProcessInformation[i].hProcess, 255);
+          WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE);
+        }
+      }
+      for (i = 0; i < cp->NumberOfCommands; ++i) {
+        /* Remove from global list of processes and close handles.  */
+        kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
+        kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
+        kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
+      }
+    }
+
+    /* Restore the working directory.  */
+    if (cp->RealWorkingDirectory) {
+      SetCurrentDirectoryW(cp->RealWorkingDirectory);
+    }
+  }
+
+  /* Free memory.  */
+  if (cp->ProcessInformation) {
+    free(cp->ProcessInformation);
+    cp->ProcessInformation = 0;
+  }
+  if (cp->ProcessEvents) {
+    free(cp->ProcessEvents);
+    cp->ProcessEvents = 0;
+  }
+  if (cp->RealWorkingDirectory) {
+    free(cp->RealWorkingDirectory);
+    cp->RealWorkingDirectory = 0;
+  }
+
+  /* Close each pipe.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
+    kwsysProcessCleanupHandle(&cp->Pipe[i].Read);
+    cp->Pipe[i].Closed = 0;
+  }
+  for (i = 0; i < 3; ++i) {
+    kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessCleanErrorMessage(kwsysProcess* cp)
+{
+  /* Remove trailing period and newline, if any.  */
+  size_t length = strlen(cp->ErrorMessage);
+  if (cp->ErrorMessage[length - 1] == '\n') {
+    cp->ErrorMessage[length - 1] = 0;
+    --length;
+    if (length > 0 && cp->ErrorMessage[length - 1] == '\r') {
+      cp->ErrorMessage[length - 1] = 0;
+      --length;
+    }
+  }
+  if (length > 0 && cp->ErrorMessage[length - 1] == '.') {
+    cp->ErrorMessage[length - 1] = 0;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the time at which either the process or user timeout will
+   expire.  Returns 1 if the user timeout is first, and 0 otherwise.  */
+int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
+                               kwsysProcessTime* timeoutTime)
+{
+  /* The first time this is called, we need to calculate the time at
+     which the child will timeout.  */
+  if (cp->Timeout && cp->TimeoutTime.QuadPart < 0) {
+    kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout);
+    cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length);
+  }
+
+  /* Start with process timeout.  */
+  *timeoutTime = cp->TimeoutTime;
+
+  /* Check if the user timeout is earlier.  */
+  if (userTimeout) {
+    kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
+    kwsysProcessTime userTimeoutLength =
+      kwsysProcessTimeFromDouble(*userTimeout);
+    kwsysProcessTime userTimeoutTime =
+      kwsysProcessTimeAdd(currentTime, userTimeoutLength);
+    if (timeoutTime->QuadPart < 0 ||
+        kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) {
+      *timeoutTime = userTimeoutTime;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the length of time before the given timeout time arrives.
+   Returns 1 if the time has already arrived, and 0 otherwise.  */
+int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
+                               double* userTimeout,
+                               kwsysProcessTime* timeoutLength)
+{
+  if (timeoutTime->QuadPart < 0) {
+    /* No timeout time has been requested.  */
+    return 0;
+  } else {
+    /* Calculate the remaining time.  */
+    kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
+    *timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime);
+
+    if (timeoutLength->QuadPart < 0 && userTimeout && *userTimeout <= 0) {
+      /* Caller has explicitly requested a zero timeout.  */
+      timeoutLength->QuadPart = 0;
+    }
+
+    if (timeoutLength->QuadPart < 0) {
+      /* Timeout has already expired.  */
+      return 1;
+    } else {
+      /* There is some time left.  */
+      return 0;
+    }
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysProcessTime kwsysProcessTimeGetCurrent()
+{
+  kwsysProcessTime current;
+  FILETIME ft;
+  GetSystemTimeAsFileTime(&ft);
+  current.LowPart = ft.dwLowDateTime;
+  current.HighPart = ft.dwHighDateTime;
+  return current;
+}
+
+/*--------------------------------------------------------------------------*/
+DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t)
+{
+  return (DWORD)(t.QuadPart * 0.0001);
+}
+
+/*--------------------------------------------------------------------------*/
+double kwsysProcessTimeToDouble(kwsysProcessTime t)
+{
+  return t.QuadPart * 0.0000001;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysProcessTime kwsysProcessTimeFromDouble(double d)
+{
+  kwsysProcessTime t;
+  t.QuadPart = (LONGLONG)(d * 10000000);
+  return t;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2)
+{
+  return in1.QuadPart < in2.QuadPart;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
+                                     kwsysProcessTime in2)
+{
+  kwsysProcessTime out;
+  out.QuadPart = in1.QuadPart + in2.QuadPart;
+  return out;
+}
+
+/*--------------------------------------------------------------------------*/
+kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
+                                          kwsysProcessTime in2)
+{
+  kwsysProcessTime out;
+  out.QuadPart = in1.QuadPart - in2.QuadPart;
+  return out;
+}
+
+/*--------------------------------------------------------------------------*/
+#define KWSYSPE_CASE(type, str)                                               \
+  cp->ExitException = kwsysProcess_Exception_##type;                          \
+  strcpy(cp->ExitExceptionString, str)
+static void kwsysProcessSetExitException(kwsysProcess* cp, int code)
+{
+  switch (code) {
+    case STATUS_CONTROL_C_EXIT:
+      KWSYSPE_CASE(Interrupt, "User interrupt");
+      break;
+
+    case STATUS_FLOAT_DENORMAL_OPERAND:
+      KWSYSPE_CASE(Numerical, "Floating-point exception (denormal operand)");
+      break;
+    case STATUS_FLOAT_DIVIDE_BY_ZERO:
+      KWSYSPE_CASE(Numerical, "Divide-by-zero");
+      break;
+    case STATUS_FLOAT_INEXACT_RESULT:
+      KWSYSPE_CASE(Numerical, "Floating-point exception (inexact result)");
+      break;
+    case STATUS_FLOAT_INVALID_OPERATION:
+      KWSYSPE_CASE(Numerical, "Invalid floating-point operation");
+      break;
+    case STATUS_FLOAT_OVERFLOW:
+      KWSYSPE_CASE(Numerical, "Floating-point overflow");
+      break;
+    case STATUS_FLOAT_STACK_CHECK:
+      KWSYSPE_CASE(Numerical, "Floating-point stack check failed");
+      break;
+    case STATUS_FLOAT_UNDERFLOW:
+      KWSYSPE_CASE(Numerical, "Floating-point underflow");
+      break;
+#ifdef STATUS_FLOAT_MULTIPLE_FAULTS
+    case STATUS_FLOAT_MULTIPLE_FAULTS:
+      KWSYSPE_CASE(Numerical, "Floating-point exception (multiple faults)");
+      break;
+#endif
+#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
+    case STATUS_FLOAT_MULTIPLE_TRAPS:
+      KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)");
+      break;
+#endif
+    case STATUS_INTEGER_DIVIDE_BY_ZERO:
+      KWSYSPE_CASE(Numerical, "Integer divide-by-zero");
+      break;
+    case STATUS_INTEGER_OVERFLOW:
+      KWSYSPE_CASE(Numerical, "Integer overflow");
+      break;
+
+    case STATUS_DATATYPE_MISALIGNMENT:
+      KWSYSPE_CASE(Fault, "Datatype misalignment");
+      break;
+    case STATUS_ACCESS_VIOLATION:
+      KWSYSPE_CASE(Fault, "Access violation");
+      break;
+    case STATUS_IN_PAGE_ERROR:
+      KWSYSPE_CASE(Fault, "In-page error");
+      break;
+    case STATUS_INVALID_HANDLE:
+      KWSYSPE_CASE(Fault, "Invalid hanlde");
+      break;
+    case STATUS_NONCONTINUABLE_EXCEPTION:
+      KWSYSPE_CASE(Fault, "Noncontinuable exception");
+      break;
+    case STATUS_INVALID_DISPOSITION:
+      KWSYSPE_CASE(Fault, "Invalid disposition");
+      break;
+    case STATUS_ARRAY_BOUNDS_EXCEEDED:
+      KWSYSPE_CASE(Fault, "Array bounds exceeded");
+      break;
+    case STATUS_STACK_OVERFLOW:
+      KWSYSPE_CASE(Fault, "Stack overflow");
+      break;
+
+    case STATUS_ILLEGAL_INSTRUCTION:
+      KWSYSPE_CASE(Illegal, "Illegal instruction");
+      break;
+    case STATUS_PRIVILEGED_INSTRUCTION:
+      KWSYSPE_CASE(Illegal, "Privileged instruction");
+      break;
+
+    case STATUS_NO_MEMORY:
+    default:
+      cp->ExitException = kwsysProcess_Exception_Other;
+      _snprintf(cp->ExitExceptionString, KWSYSPE_PIPE_BUFFER_SIZE,
+                "Exit code 0x%x\n", code);
+      break;
+  }
+}
+#undef KWSYSPE_CASE
+
+typedef struct kwsysProcess_List_s kwsysProcess_List;
+static kwsysProcess_List* kwsysProcess_List_New(void);
+static void kwsysProcess_List_Delete(kwsysProcess_List* self);
+static int kwsysProcess_List_Update(kwsysProcess_List* self);
+static int kwsysProcess_List_NextProcess(kwsysProcess_List* self);
+static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self);
+static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self);
+
+/*--------------------------------------------------------------------------*/
+/* Windows NT 4 API definitions.  */
+#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
+typedef LONG NTSTATUS;
+typedef LONG KPRIORITY;
+typedef struct _UNICODE_STRING UNICODE_STRING;
+struct _UNICODE_STRING
+{
+  USHORT Length;
+  USHORT MaximumLength;
+  PWSTR Buffer;
+};
+
+/* The process information structure.  Declare only enough to get
+   process identifiers.  The rest may be ignored because we use the
+   NextEntryDelta to move through an array of instances.  */
+typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION;
+typedef SYSTEM_PROCESS_INFORMATION* PSYSTEM_PROCESS_INFORMATION;
+struct _SYSTEM_PROCESS_INFORMATION
+{
+  ULONG NextEntryDelta;
+  ULONG ThreadCount;
+  ULONG Reserved1[6];
+  LARGE_INTEGER CreateTime;
+  LARGE_INTEGER UserTime;
+  LARGE_INTEGER KernelTime;
+  UNICODE_STRING ProcessName;
+  KPRIORITY BasePriority;
+  ULONG ProcessId;
+  ULONG InheritedFromProcessId;
+};
+
+/*--------------------------------------------------------------------------*/
+/* Toolhelp32 API definitions.  */
+#define TH32CS_SNAPPROCESS 0x00000002
+#if defined(_WIN64)
+typedef unsigned __int64 ProcessULONG_PTR;
+#else
+typedef unsigned long ProcessULONG_PTR;
+#endif
+typedef struct tagPROCESSENTRY32 PROCESSENTRY32;
+typedef PROCESSENTRY32* LPPROCESSENTRY32;
+struct tagPROCESSENTRY32
+{
+  DWORD dwSize;
+  DWORD cntUsage;
+  DWORD th32ProcessID;
+  ProcessULONG_PTR th32DefaultHeapID;
+  DWORD th32ModuleID;
+  DWORD cntThreads;
+  DWORD th32ParentProcessID;
+  LONG pcPriClassBase;
+  DWORD dwFlags;
+  char szExeFile[MAX_PATH];
+};
+
+/*--------------------------------------------------------------------------*/
+/* Windows API function types.  */
+typedef HANDLE(WINAPI* CreateToolhelp32SnapshotType)(DWORD, DWORD);
+typedef BOOL(WINAPI* Process32FirstType)(HANDLE, LPPROCESSENTRY32);
+typedef BOOL(WINAPI* Process32NextType)(HANDLE, LPPROCESSENTRY32);
+typedef NTSTATUS(WINAPI* ZwQuerySystemInformationType)(ULONG, PVOID, ULONG,
+                                                       PULONG);
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__New_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self);
+static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self);
+static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self);
+static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self);
+static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self);
+static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self);
+static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self);
+static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self);
+
+struct kwsysProcess_List_s
+{
+  /* Implementation switches at runtime based on version of Windows.  */
+  int NT4;
+
+  /* Implementation functions and data for NT 4.  */
+  ZwQuerySystemInformationType P_ZwQuerySystemInformation;
+  char* Buffer;
+  int BufferSize;
+  PSYSTEM_PROCESS_INFORMATION CurrentInfo;
+
+  /* Implementation functions and data for other Windows versions.  */
+  CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot;
+  Process32FirstType P_Process32First;
+  Process32NextType P_Process32Next;
+  HANDLE Snapshot;
+  PROCESSENTRY32 CurrentEntry;
+};
+
+/*--------------------------------------------------------------------------*/
+static kwsysProcess_List* kwsysProcess_List_New(void)
+{
+  OSVERSIONINFO osv;
+  kwsysProcess_List* self;
+
+  /* Allocate and initialize the list object.  */
+  if (!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List)))) {
+    return 0;
+  }
+  memset(self, 0, sizeof(*self));
+
+  /* Select an implementation.  */
+  ZeroMemory(&osv, sizeof(osv));
+  osv.dwOSVersionInfoSize = sizeof(osv);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(push)
+#ifdef __INTEL_COMPILER
+#pragma warning(disable : 1478)
+#else
+#pragma warning(disable : 4996)
+#endif
+#endif
+  GetVersionEx(&osv);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(pop)
+#endif
+  self->NT4 =
+    (osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1
+                                                                          : 0;
+
+  /* Initialize the selected implementation.  */
+  if (!(self->NT4 ? kwsysProcess_List__New_NT4(self)
+                  : kwsysProcess_List__New_Snapshot(self))) {
+    kwsysProcess_List_Delete(self);
+    return 0;
+  }
+
+  /* Update to the current set of processes.  */
+  if (!kwsysProcess_List_Update(self)) {
+    kwsysProcess_List_Delete(self);
+    return 0;
+  }
+  return self;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcess_List_Delete(kwsysProcess_List* self)
+{
+  if (self) {
+    if (self->NT4) {
+      kwsysProcess_List__Delete_NT4(self);
+    } else {
+      kwsysProcess_List__Delete_Snapshot(self);
+    }
+    free(self);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List_Update(kwsysProcess_List* self)
+{
+  return self ? (self->NT4 ? kwsysProcess_List__Update_NT4(self)
+                           : kwsysProcess_List__Update_Snapshot(self))
+              : 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self)
+{
+  return self ? (self->NT4 ? kwsysProcess_List__GetProcessId_NT4(self)
+                           : kwsysProcess_List__GetProcessId_Snapshot(self))
+              : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self)
+{
+  return self ? (self->NT4 ? kwsysProcess_List__GetParentId_NT4(self)
+                           : kwsysProcess_List__GetParentId_Snapshot(self))
+              : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List_NextProcess(kwsysProcess_List* self)
+{
+  return (self ? (self->NT4 ? kwsysProcess_List__Next_NT4(self)
+                            : kwsysProcess_List__Next_Snapshot(self))
+               : 0);
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__New_NT4(kwsysProcess_List* self)
+{
+  /* Get a handle to the NT runtime module that should already be
+     loaded in this program.  This does not actually increment the
+     reference count to the module so we do not need to close the
+     handle.  */
+  HMODULE hNT = GetModuleHandleW(L"ntdll.dll");
+  if (hNT) {
+    /* Get pointers to the needed API functions.  */
+    self->P_ZwQuerySystemInformation =
+      ((ZwQuerySystemInformationType)GetProcAddress(
+        hNT, "ZwQuerySystemInformation"));
+  }
+  if (!self->P_ZwQuerySystemInformation) {
+    return 0;
+  }
+
+  /* Allocate an initial process information buffer.  */
+  self->BufferSize = 32768;
+  self->Buffer = (char*)malloc(self->BufferSize);
+  return self->Buffer ? 1 : 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self)
+{
+  /* Free the process information buffer.  */
+  if (self->Buffer) {
+    free(self->Buffer);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self)
+{
+  self->CurrentInfo = 0;
+  for (;;) {
+    /* Query number 5 is for system process list.  */
+    NTSTATUS status =
+      self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0);
+    if (status == STATUS_INFO_LENGTH_MISMATCH) {
+      /* The query requires a bigger buffer.  */
+      int newBufferSize = self->BufferSize * 2;
+      char* newBuffer = (char*)malloc(newBufferSize);
+      if (newBuffer) {
+        free(self->Buffer);
+        self->Buffer = newBuffer;
+        self->BufferSize = newBufferSize;
+      } else {
+        return 0;
+      }
+    } else if (status >= 0) {
+      /* The query succeeded.  Initialize traversal of the process list.  */
+      self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer;
+      return 1;
+    } else {
+      /* The query failed.  */
+      return 0;
+    }
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self)
+{
+  if (self->CurrentInfo) {
+    if (self->CurrentInfo->NextEntryDelta > 0) {
+      self->CurrentInfo = ((PSYSTEM_PROCESS_INFORMATION)(
+        (char*)self->CurrentInfo + self->CurrentInfo->NextEntryDelta));
+      return 1;
+    }
+    self->CurrentInfo = 0;
+  }
+  return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self)
+{
+  return self->CurrentInfo ? self->CurrentInfo->ProcessId : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self)
+{
+  return self->CurrentInfo ? self->CurrentInfo->InheritedFromProcessId : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self)
+{
+  /* Get a handle to the Windows runtime module that should already be
+     loaded in this program.  This does not actually increment the
+     reference count to the module so we do not need to close the
+     handle.  */
+  HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
+  if (hKernel) {
+    self->P_CreateToolhelp32Snapshot =
+      ((CreateToolhelp32SnapshotType)GetProcAddress(
+        hKernel, "CreateToolhelp32Snapshot"));
+    self->P_Process32First =
+      ((Process32FirstType)GetProcAddress(hKernel, "Process32First"));
+    self->P_Process32Next =
+      ((Process32NextType)GetProcAddress(hKernel, "Process32Next"));
+  }
+  return (self->P_CreateToolhelp32Snapshot && self->P_Process32First &&
+          self->P_Process32Next)
+    ? 1
+    : 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self)
+{
+  if (self->Snapshot) {
+    CloseHandle(self->Snapshot);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self)
+{
+  if (self->Snapshot) {
+    CloseHandle(self->Snapshot);
+  }
+  if (!(self->Snapshot =
+          self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) {
+    return 0;
+  }
+  ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry));
+  self->CurrentEntry.dwSize = sizeof(self->CurrentEntry);
+  if (!self->P_Process32First(self->Snapshot, &self->CurrentEntry)) {
+    CloseHandle(self->Snapshot);
+    self->Snapshot = 0;
+    return 0;
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self)
+{
+  if (self->Snapshot) {
+    if (self->P_Process32Next(self->Snapshot, &self->CurrentEntry)) {
+      return 1;
+    }
+    CloseHandle(self->Snapshot);
+    self->Snapshot = 0;
+  }
+  return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self)
+{
+  return self->Snapshot ? self->CurrentEntry.th32ProcessID : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self)
+{
+  return self->Snapshot ? self->CurrentEntry.th32ParentProcessID : -1;
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessKill(DWORD pid)
+{
+  HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid);
+  if (h) {
+    TerminateProcess(h, 255);
+    WaitForSingleObject(h, INFINITE);
+    CloseHandle(h);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessKillTree(int pid)
+{
+  kwsysProcess_List* plist = kwsysProcess_List_New();
+  kwsysProcessKill(pid);
+  if (plist) {
+    do {
+      if (kwsysProcess_List_GetCurrentParentId(plist) == pid) {
+        int ppid = kwsysProcess_List_GetCurrentProcessId(plist);
+        kwsysProcessKillTree(ppid);
+      }
+    } while (kwsysProcess_List_NextProcess(plist));
+    kwsysProcess_List_Delete(plist);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessDisablePipeThreads(kwsysProcess* cp)
+{
+  int i;
+
+  /* If data were just reported data, release the pipe's thread.  */
+  if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
+    KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
+    ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
+    cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
+  }
+
+  /* Wakeup all reading threads that are not on closed pipes.  */
+  for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
+    /* The wakeup threads will write one byte to the pipe write ends.
+       If there are no data in the pipe then this is enough to wakeup
+       the reading threads.  If there are already data in the pipe
+       this may block.  We cannot use PeekNamedPipe to check whether
+       there are data because an outside process might still be
+       writing data if we are disowning it.  Also, PeekNamedPipe will
+       block if checking a pipe on which the reading thread is
+       currently calling ReadPipe.  Therefore we need a separate
+       thread to call WriteFile.  If it blocks, that is okay because
+       it will unblock when we close the read end and break the pipe
+       below.  */
+    if (cp->Pipe[i].Read) {
+      KWSYSPE_DEBUG((stderr, "releasing waker %d\n", i));
+      ReleaseSemaphore(cp->Pipe[i].Waker.Go, 1, 0);
+    }
+  }
+
+  /* Tell pipe threads to reset until we run another process.  */
+  while (cp->PipesLeft > 0) {
+    /* The waking threads will cause all reading threads to report.
+       Wait for the next one and save its index.  */
+    KWSYSPE_DEBUG((stderr, "waiting for reader\n"));
+    WaitForSingleObject(cp->Full, INFINITE);
+    cp->CurrentIndex = cp->SharedIndex;
+    ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
+    KWSYSPE_DEBUG((stderr, "got reader %d\n", cp->CurrentIndex));
+
+    /* We are done reading this pipe.  Close its read handle.  */
+    cp->Pipe[cp->CurrentIndex].Closed = 1;
+    kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read);
+    --cp->PipesLeft;
+
+    /* Tell the reading thread we are done with the data.  It will
+       reset immediately because the pipe is closed.  */
+    ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Global set of executing processes for use by the Ctrl handler.
+   This global instance will be zero-initialized by the compiler.
+
+   Note that the console Ctrl handler runs on a background thread and so
+   everything it does must be thread safe.  Here, we track the hProcess
+   HANDLEs directly instead of kwsysProcess instances, so that we don't have
+   to make kwsysProcess thread safe.  */
+typedef struct kwsysProcessInstance_s
+{
+  HANDLE hProcess;
+  DWORD dwProcessId;
+  int NewProcessGroup; /* Whether the process was created in a new group.  */
+} kwsysProcessInstance;
+
+typedef struct kwsysProcessInstances_s
+{
+  /* Whether we have initialized key fields below, like critical sections.  */
+  int Initialized;
+
+  /* Ctrl handler runs on a different thread, so we must sync access.  */
+  CRITICAL_SECTION Lock;
+
+  int Exiting;
+  size_t Count;
+  size_t Size;
+  kwsysProcessInstance* Processes;
+} kwsysProcessInstances;
+static kwsysProcessInstances kwsysProcesses;
+
+/*--------------------------------------------------------------------------*/
+/* Initialize critial section and set up console Ctrl handler.  You MUST call
+   this before using any other kwsysProcesses* functions below.  */
+static int kwsysProcessesInitialize(void)
+{
+  /* Initialize everything if not done already.  */
+  if (!kwsysProcesses.Initialized) {
+    InitializeCriticalSection(&kwsysProcesses.Lock);
+
+    /* Set up console ctrl handler.  */
+    if (!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE)) {
+      return 0;
+    }
+
+    kwsysProcesses.Initialized = 1;
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* The Ctrl handler waits on the global list of processes.  To prevent an
+   orphaned process, do not create a new process if the Ctrl handler is
+   already running.  Do so by using this function to check if it is ok to
+   create a process.  */
+static int kwsysTryEnterCreateProcessSection(void)
+{
+  /* Enter main critical section; this means creating a process and the Ctrl
+     handler are mutually exclusive.  */
+  EnterCriticalSection(&kwsysProcesses.Lock);
+  /* Indicate to the caller if they can create a process.  */
+  if (kwsysProcesses.Exiting) {
+    LeaveCriticalSection(&kwsysProcesses.Lock);
+    return 0;
+  } else {
+    return 1;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Matching function on successful kwsysTryEnterCreateProcessSection return.
+   Make sure you called kwsysProcessesAdd if applicable before calling this.*/
+static void kwsysLeaveCreateProcessSection(void)
+{
+  LeaveCriticalSection(&kwsysProcesses.Lock);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Add new process to global process list.  The Ctrl handler will wait for
+   the process to exit before it returns.  Do not close the process handle
+   until after calling kwsysProcessesRemove.  The newProcessGroup parameter
+   must be set if the process was created with CREATE_NEW_PROCESS_GROUP.  */
+static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid,
+                             int newProcessGroup)
+{
+  if (!kwsysProcessesInitialize() || !hProcess ||
+      hProcess == INVALID_HANDLE_VALUE) {
+    return 0;
+  }
+
+  /* Enter the critical section. */
+  EnterCriticalSection(&kwsysProcesses.Lock);
+
+  /* Make sure there is enough space for the new process handle.  */
+  if (kwsysProcesses.Count == kwsysProcesses.Size) {
+    size_t newSize;
+    kwsysProcessInstance* newArray;
+    /* Start with enough space for a small number of process handles
+       and double the size each time more is needed.  */
+    newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4;
+
+    /* Try allocating the new block of memory.  */
+    if (newArray = (kwsysProcessInstance*)malloc(
+          newSize * sizeof(kwsysProcessInstance))) {
+      /* Copy the old process handles to the new memory.  */
+      if (kwsysProcesses.Count > 0) {
+        memcpy(newArray, kwsysProcesses.Processes,
+               kwsysProcesses.Count * sizeof(kwsysProcessInstance));
+      }
+    } else {
+      /* Failed to allocate memory for the new process handle set.  */
+      LeaveCriticalSection(&kwsysProcesses.Lock);
+      return 0;
+    }
+
+    /* Free original array. */
+    free(kwsysProcesses.Processes);
+
+    /* Update original structure with new allocation. */
+    kwsysProcesses.Size = newSize;
+    kwsysProcesses.Processes = newArray;
+  }
+
+  /* Append the new process information to the set.  */
+  kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess;
+  kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid;
+  kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup =
+    newProcessGroup;
+
+  /* Leave critical section and return success. */
+  LeaveCriticalSection(&kwsysProcesses.Lock);
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Removes process to global process list.  */
+static void kwsysProcessesRemove(HANDLE hProcess)
+{
+  size_t i;
+
+  if (!hProcess || hProcess == INVALID_HANDLE_VALUE) {
+    return;
+  }
+
+  EnterCriticalSection(&kwsysProcesses.Lock);
+
+  /* Find the given process in the set.  */
+  for (i = 0; i < kwsysProcesses.Count; ++i) {
+    if (kwsysProcesses.Processes[i].hProcess == hProcess) {
+      break;
+    }
+  }
+  if (i < kwsysProcesses.Count) {
+    /* Found it!  Remove the process from the set.  */
+    --kwsysProcesses.Count;
+    for (; i < kwsysProcesses.Count; ++i) {
+      kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i + 1];
+    }
+
+    /* If this was the last process, free the array.  */
+    if (kwsysProcesses.Count == 0) {
+      kwsysProcesses.Size = 0;
+      free(kwsysProcesses.Processes);
+      kwsysProcesses.Processes = 0;
+    }
+  }
+
+  LeaveCriticalSection(&kwsysProcesses.Lock);
+}
+
+/*--------------------------------------------------------------------------*/
+static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType)
+{
+  size_t i;
+  (void)dwCtrlType;
+  /* Enter critical section.  */
+  EnterCriticalSection(&kwsysProcesses.Lock);
+
+  /* Set flag indicating that we are exiting.  */
+  kwsysProcesses.Exiting = 1;
+
+  /* If some of our processes were created in a new process group, we must
+     manually interrupt them.  They won't otherwise receive a Ctrl+C/Break. */
+  for (i = 0; i < kwsysProcesses.Count; ++i) {
+    if (kwsysProcesses.Processes[i].NewProcessGroup) {
+      DWORD groupId = kwsysProcesses.Processes[i].dwProcessId;
+      if (groupId) {
+        GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId);
+      }
+    }
+  }
+
+  /* Wait for each child process to exit.  This is the key step that prevents
+     us from leaving several orphaned children processes running in the
+     background when the user presses Ctrl+C.  */
+  for (i = 0; i < kwsysProcesses.Count; ++i) {
+    WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE);
+  }
+
+  /* Leave critical section.  */
+  LeaveCriticalSection(&kwsysProcesses.Lock);
+
+  /* Continue on to default Ctrl handler (which calls ExitProcess).  */
+  return FALSE;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_ResetStartTime(kwsysProcess* cp)
+{
+  if (!cp) {
+    return;
+  }
+  /* Reset start time. */
+  cp->StartTime = kwsysProcessTimeGetCurrent();
+}
diff --git a/thirdparty/KWSys/adios2sys/README.rst b/thirdparty/KWSys/adios2sys/README.rst
new file mode 100644
index 0000000000000000000000000000000000000000..fc6b5902edcfe5a5c58d15868eef969d22d7374c
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/README.rst
@@ -0,0 +1,37 @@
+KWSys
+*****
+
+Introduction
+============
+
+KWSys is the Kitware System Library.  It provides platform-independent
+APIs to many common system features that are implemented differently on
+every platform.  This library is intended to be shared among many
+projects at the source level, so it has a configurable namespace.
+Each project should configure KWSys to use a namespace unique to itself.
+See comments in `CMakeLists.txt`_ for details.
+
+.. _`CMakeLists.txt`: CMakeLists.txt
+
+License
+=======
+
+KWSys is distributed under the OSI-approved BSD 3-clause License.
+See `Copyright.txt`_ for details.
+
+.. _`Copyright.txt`: Copyright.txt
+
+Reporting Bugs
+==============
+
+KWSys has no independent issue tracker.  After encountering an issue
+(bug) please submit a patch using the instructions for `Contributing`_.
+Otherwise please report the issue to the tracker for the project that
+hosts the copy of KWSys in which the problem was found.
+
+Contributing
+============
+
+See `CONTRIBUTING.rst`_ for instructions to contribute.
+
+.. _`CONTRIBUTING.rst`: CONTRIBUTING.rst
diff --git a/thirdparty/KWSys/adios2sys/RegularExpression.cxx b/thirdparty/KWSys/adios2sys/RegularExpression.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6d7f832955911e5352e6f60e246b743c37c3ebdb
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/RegularExpression.cxx
@@ -0,0 +1,1214 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+//
+// Copyright (C) 1991 Texas Instruments Incorporated.
+//
+// Permission is granted to any individual or institution to use, copy, modify
+// and distribute this software, provided that this complete copyright and
+// permission notice is maintained, intact, in all copies and supporting
+// documentation.
+//
+// Texas Instruments Incorporated provides this software "as is" without
+// express or implied warranty.
+//
+//
+// Created: MNF 06/13/89  Initial Design and Implementation
+// Updated: LGO 08/09/89  Inherit from Generic
+// Updated: MBN 09/07/89  Added conditional exception handling
+// Updated: MBN 12/15/89  Sprinkled "const" qualifiers all over the place!
+// Updated: DLS 03/22/91  New lite version
+//
+
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(RegularExpression.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "RegularExpression.hxx.in"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+namespace KWSYS_NAMESPACE {
+
+// RegularExpression -- Copies the given regular expression.
+RegularExpression::RegularExpression(const RegularExpression& rxp)
+{
+  if (!rxp.program) {
+    this->program = 0;
+    return;
+  }
+  int ind;
+  this->progsize = rxp.progsize;            // Copy regular expression size
+  this->program = new char[this->progsize]; // Allocate storage
+  for (ind = this->progsize; ind-- != 0;)   // Copy regular expresion
+    this->program[ind] = rxp.program[ind];
+  this->startp[0] = rxp.startp[0]; // Copy pointers into last
+  this->endp[0] = rxp.endp[0];     // Successful "find" operation
+  this->regmust = rxp.regmust;     // Copy field
+  if (rxp.regmust != 0) {
+    char* dum = rxp.program;
+    ind = 0;
+    while (dum != rxp.regmust) {
+      ++dum;
+      ++ind;
+    }
+    this->regmust = this->program + ind;
+  }
+  this->regstart = rxp.regstart; // Copy starting index
+  this->reganch = rxp.reganch;   // Copy remaining private data
+  this->regmlen = rxp.regmlen;   // Copy remaining private data
+}
+
+// operator= -- Copies the given regular expression.
+RegularExpression& RegularExpression::operator=(const RegularExpression& rxp)
+{
+  if (this == &rxp) {
+    return *this;
+  }
+  if (!rxp.program) {
+    this->program = 0;
+    return *this;
+  }
+  int ind;
+  this->progsize = rxp.progsize; // Copy regular expression size
+  delete[] this->program;
+  this->program = new char[this->progsize]; // Allocate storage
+  for (ind = this->progsize; ind-- != 0;)   // Copy regular expresion
+    this->program[ind] = rxp.program[ind];
+  this->startp[0] = rxp.startp[0]; // Copy pointers into last
+  this->endp[0] = rxp.endp[0];     // Successful "find" operation
+  this->regmust = rxp.regmust;     // Copy field
+  if (rxp.regmust != 0) {
+    char* dum = rxp.program;
+    ind = 0;
+    while (dum != rxp.regmust) {
+      ++dum;
+      ++ind;
+    }
+    this->regmust = this->program + ind;
+  }
+  this->regstart = rxp.regstart; // Copy starting index
+  this->reganch = rxp.reganch;   // Copy remaining private data
+  this->regmlen = rxp.regmlen;   // Copy remaining private data
+
+  return *this;
+}
+
+// operator== -- Returns true if two regular expressions have the same
+// compiled program for pattern matching.
+bool RegularExpression::operator==(const RegularExpression& rxp) const
+{
+  if (this != &rxp) {         // Same address?
+    int ind = this->progsize; // Get regular expression size
+    if (ind != rxp.progsize)  // If different size regexp
+      return false;           // Return failure
+    while (ind-- != 0)        // Else while still characters
+      if (this->program[ind] != rxp.program[ind]) // If regexp are different
+        return false;                             // Return failure
+  }
+  return true; // Else same, return success
+}
+
+// deep_equal -- Returns true if have the same compiled regular expressions
+// and the same start and end pointers.
+
+bool RegularExpression::deep_equal(const RegularExpression& rxp) const
+{
+  int ind = this->progsize;                     // Get regular expression size
+  if (ind != rxp.progsize)                      // If different size regexp
+    return false;                               // Return failure
+  while (ind-- != 0)                            // Else while still characters
+    if (this->program[ind] != rxp.program[ind]) // If regexp are different
+      return false;                             // Return failure
+  return (this->startp[0] == rxp.startp[0] &&   // Else if same start/end ptrs,
+          this->endp[0] == rxp.endp[0]);        // Return true
+}
+
+// The remaining code in this file is derived from the  regular expression code
+// whose  copyright statement appears  below.  It has been  changed to work
+// with the class concepts of C++ and COOL.
+
+/*
+ * compile and find
+ *
+ *      Copyright (c) 1986 by University of Toronto.
+ *      Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *      Permission is granted to anyone to use this software for any
+ *      purpose on any computer system, and to redistribute it freely,
+ *      subject to the following restrictions:
+ *
+ *      1. The author is not responsible for the consequences of use of
+ *              this software, no matter how awful, even if they arise
+ *              from defects in it.
+ *
+ *      2. The origin of this software must not be misrepresented, either
+ *              by explicit claim or by omission.
+ *
+ *      3. Altered versions must be plainly marked as such, and must not
+ *              be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions.  Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases.  They are:
+ *
+ * regstart     char that must begin a match; '\0' if none obvious
+ * reganch      is the match anchored (at beginning-of-line only)?
+ * regmust      string (pointer into program) that match must include, or NULL
+ * regmlen      length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
+ * of lines that cannot possibly match.  The regmust tests are costly enough
+ * that compile() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
+ * supplied because the test in find() needs it and compile() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program".  This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology).  Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
+ * have one of the subtle syntax dependencies:  an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.)  The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM.  In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure:  the tail of the branch connects
+ * to the thing following the set of BRANCHes.)  The opcodes are:
+ */
+
+// definition   number  opnd?   meaning
+#define END 0     // no   End of program.
+#define BOL 1     // no   Match "" at beginning of line.
+#define EOL 2     // no   Match "" at end of line.
+#define ANY 3     // no   Match any one character.
+#define ANYOF 4   // str  Match any character in this string.
+#define ANYBUT 5  // str  Match any character not in this
+                  // string.
+#define BRANCH 6  // node Match this alternative, or the
+                  // next...
+#define BACK 7    // no   Match "", "next" ptr points backward.
+#define EXACTLY 8 // str  Match this string.
+#define NOTHING 9 // no   Match empty string.
+#define STAR 10   // node Match this (simple) thing 0 or more
+                  // times.
+#define PLUS 11   // node Match this (simple) thing 1 or more
+                  // times.
+#define OPEN 20   // no   Mark this point in input as start of
+                  // #n.
+// OPEN+1 is number 1, etc.
+#define CLOSE 30 // no   Analogous to OPEN.
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH       The set of branches constituting a single choice are hooked
+ *              together with their "next" pointers, since precedence prevents
+ *              anything being concatenated to any individual branch.  The
+ *              "next" pointer of the last BRANCH in a choice points to the
+ *              thing following the whole choice.  This is also where the
+ *              final "next" pointer of each individual branch points; each
+ *              branch starts with the operand node of a BRANCH node.
+ *
+ * BACK         Normal "next" pointers all implicitly point forward; BACK
+ *              exists to make loop structures possible.
+ *
+ * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
+ *              BRANCH structures using BACK.  Simple cases (one character
+ *              per match) are implemented with STAR and PLUS for speed
+ *              and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE   ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node.  (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377))
+#define OPERAND(p) ((p) + 3)
+
+const unsigned char MAGIC = 0234;
+/*
+ * Utility definitions.
+ */
+
+#define UCHARAT(p) (reinterpret_cast<const unsigned char*>(p))[0]
+
+#define FAIL(m)                                                               \
+  {                                                                           \
+    regerror(m);                                                              \
+    return (0);                                                               \
+  }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
+#define META "^$.[()|?+*\\"
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 // Known never to match null string.
+#define SIMPLE 02   // Simple enough to be STAR/PLUS operand.
+#define SPSTART 04  // Starts with * or +.
+#define WORST 0     // Worst case.
+
+/////////////////////////////////////////////////////////////////////////
+//
+//  COMPILE AND ASSOCIATED FUNCTIONS
+//
+/////////////////////////////////////////////////////////////////////////
+
+/*
+ * Global work variables for compile().
+ */
+static const char* regparse; // Input-scan pointer.
+static int regnpar;          // () count.
+static char regdummy;
+static char* regcode; // Code-emit pointer; &regdummy = don't.
+static long regsize;  // Code size.
+
+/*
+ * Forward declarations for compile()'s friends.
+ */
+// #ifndef static
+// #define      static  static
+// #endif
+static char* reg(int, int*);
+static char* regbranch(int*);
+static char* regpiece(int*);
+static char* regatom(int*);
+static char* regnode(char);
+static const char* regnext(const char*);
+static char* regnext(char*);
+static void regc(char);
+static void reginsert(char, char*);
+static void regtail(char*, const char*);
+static void regoptail(char*, const char*);
+
+#ifdef STRCSPN
+static int strcspn();
+#endif
+
+/*
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code.  So we cheat:  we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it.  (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+
+// compile -- compile a regular expression into internal code
+// for later pattern matching.
+
+bool RegularExpression::compile(const char* exp)
+{
+  const char* scan;
+  const char* longest;
+  size_t len;
+  int flags;
+
+  if (exp == 0) {
+    // RAISE Error, SYM(RegularExpression), SYM(No_Expr),
+    printf("RegularExpression::compile(): No expression supplied.\n");
+    return false;
+  }
+
+  // First pass: determine size, legality.
+  regparse = exp;
+  regnpar = 1;
+  regsize = 0L;
+  regcode = &regdummy;
+  regc(static_cast<char>(MAGIC));
+  if (!reg(0, &flags)) {
+    printf("RegularExpression::compile(): Error in compile.\n");
+    return false;
+  }
+  this->startp[0] = this->endp[0] = this->searchstring = 0;
+
+  // Small enough for pointer-storage convention?
+  if (regsize >= 32767L) { // Probably could be 65535L.
+    // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big),
+    printf("RegularExpression::compile(): Expression too big.\n");
+    return false;
+  }
+
+  // Allocate space.
+  //#ifndef _WIN32
+  if (this->program != 0)
+    delete[] this->program;
+  //#endif
+  this->program = new char[regsize];
+  this->progsize = static_cast<int>(regsize);
+
+  if (this->program == 0) {
+    // RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory),
+    printf("RegularExpression::compile(): Out of memory.\n");
+    return false;
+  }
+
+  // Second pass: emit code.
+  regparse = exp;
+  regnpar = 1;
+  regcode = this->program;
+  regc(static_cast<char>(MAGIC));
+  reg(0, &flags);
+
+  // Dig out information for optimizations.
+  this->regstart = '\0'; // Worst-case defaults.
+  this->reganch = 0;
+  this->regmust = 0;
+  this->regmlen = 0;
+  scan = this->program + 1;       // First BRANCH.
+  if (OP(regnext(scan)) == END) { // Only one top-level choice.
+    scan = OPERAND(scan);
+
+    // Starting-point info.
+    if (OP(scan) == EXACTLY)
+      this->regstart = *OPERAND(scan);
+    else if (OP(scan) == BOL)
+      this->reganch++;
+
+    //
+    // If there's something expensive in the r.e., find the longest
+    // literal string that must appear and make it the regmust.  Resolve
+    // ties in favor of later strings, since the regstart check works
+    // with the beginning of the r.e. and avoiding duplication
+    // strengthens checking.  Not a strong reason, but sufficient in the
+    // absence of others.
+    //
+    if (flags & SPSTART) {
+      longest = 0;
+      len = 0;
+      for (; scan != 0; scan = regnext(scan))
+        if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+          longest = OPERAND(scan);
+          len = strlen(OPERAND(scan));
+        }
+      this->regmust = longest;
+      this->regmlen = len;
+    }
+  }
+  return true;
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char* reg(int paren, int* flagp)
+{
+  char* ret;
+  char* br;
+  char* ender;
+  int parno = 0;
+  int flags;
+
+  *flagp = HASWIDTH; // Tentatively.
+
+  // Make an OPEN node, if parenthesized.
+  if (paren) {
+    if (regnpar >= RegularExpression::NSUBEXP) {
+      // RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens),
+      printf("RegularExpression::compile(): Too many parentheses.\n");
+      return 0;
+    }
+    parno = regnpar;
+    regnpar++;
+    ret = regnode(static_cast<char>(OPEN + parno));
+  } else
+    ret = 0;
+
+  // Pick up the branches, linking them together.
+  br = regbranch(&flags);
+  if (br == 0)
+    return (0);
+  if (ret != 0)
+    regtail(ret, br); // OPEN -> first.
+  else
+    ret = br;
+  if (!(flags & HASWIDTH))
+    *flagp &= ~HASWIDTH;
+  *flagp |= flags & SPSTART;
+  while (*regparse == '|') {
+    regparse++;
+    br = regbranch(&flags);
+    if (br == 0)
+      return (0);
+    regtail(ret, br); // BRANCH -> BRANCH.
+    if (!(flags & HASWIDTH))
+      *flagp &= ~HASWIDTH;
+    *flagp |= flags & SPSTART;
+  }
+
+  // Make a closing node, and hook it on the end.
+  ender = regnode(static_cast<char>((paren) ? CLOSE + parno : END));
+  regtail(ret, ender);
+
+  // Hook the tails of the branches to the closing node.
+  for (br = ret; br != 0; br = regnext(br))
+    regoptail(br, ender);
+
+  // Check for proper termination.
+  if (paren && *regparse++ != ')') {
+    // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
+    printf("RegularExpression::compile(): Unmatched parentheses.\n");
+    return 0;
+  } else if (!paren && *regparse != '\0') {
+    if (*regparse == ')') {
+      // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
+      printf("RegularExpression::compile(): Unmatched parentheses.\n");
+      return 0;
+    } else {
+      // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+      printf("RegularExpression::compile(): Internal error.\n");
+      return 0;
+    }
+    // NOTREACHED
+  }
+  return (ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char* regbranch(int* flagp)
+{
+  char* ret;
+  char* chain;
+  char* latest;
+  int flags;
+
+  *flagp = WORST; // Tentatively.
+
+  ret = regnode(BRANCH);
+  chain = 0;
+  while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
+    latest = regpiece(&flags);
+    if (latest == 0)
+      return (0);
+    *flagp |= flags & HASWIDTH;
+    if (chain == 0) // First piece.
+      *flagp |= flags & SPSTART;
+    else
+      regtail(chain, latest);
+    chain = latest;
+  }
+  if (chain == 0) // Loop ran zero times.
+    regnode(NOTHING);
+
+  return (ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char* regpiece(int* flagp)
+{
+  char* ret;
+  char op;
+  char* next;
+  int flags;
+
+  ret = regatom(&flags);
+  if (ret == 0)
+    return (0);
+
+  op = *regparse;
+  if (!ISMULT(op)) {
+    *flagp = flags;
+    return (ret);
+  }
+
+  if (!(flags & HASWIDTH) && op != '?') {
+    // RAISE Error, SYM(RegularExpression), SYM(Empty_Operand),
+    printf("RegularExpression::compile() : *+ operand could be empty.\n");
+    return 0;
+  }
+  *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
+
+  if (op == '*' && (flags & SIMPLE))
+    reginsert(STAR, ret);
+  else if (op == '*') {
+    // Emit x* as (x&|), where & means "self".
+    reginsert(BRANCH, ret);         // Either x
+    regoptail(ret, regnode(BACK));  // and loop
+    regoptail(ret, ret);            // back
+    regtail(ret, regnode(BRANCH));  // or
+    regtail(ret, regnode(NOTHING)); // null.
+  } else if (op == '+' && (flags & SIMPLE))
+    reginsert(PLUS, ret);
+  else if (op == '+') {
+    // Emit x+ as x(&|), where & means "self".
+    next = regnode(BRANCH); // Either
+    regtail(ret, next);
+    regtail(regnode(BACK), ret);    // loop back
+    regtail(next, regnode(BRANCH)); // or
+    regtail(ret, regnode(NOTHING)); // null.
+  } else if (op == '?') {
+    // Emit x? as (x|)
+    reginsert(BRANCH, ret);        // Either x
+    regtail(ret, regnode(BRANCH)); // or
+    next = regnode(NOTHING);       // null.
+    regtail(ret, next);
+    regoptail(ret, next);
+  }
+  regparse++;
+  if (ISMULT(*regparse)) {
+    // RAISE Error, SYM(RegularExpression), SYM(Nested_Operand),
+    printf("RegularExpression::compile(): Nested *?+.\n");
+    return 0;
+  }
+  return (ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.  Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char* regatom(int* flagp)
+{
+  char* ret;
+  int flags;
+
+  *flagp = WORST; // Tentatively.
+
+  switch (*regparse++) {
+    case '^':
+      ret = regnode(BOL);
+      break;
+    case '$':
+      ret = regnode(EOL);
+      break;
+    case '.':
+      ret = regnode(ANY);
+      *flagp |= HASWIDTH | SIMPLE;
+      break;
+    case '[': {
+      int rxpclass;
+      int rxpclassend;
+
+      if (*regparse == '^') { // Complement of range.
+        ret = regnode(ANYBUT);
+        regparse++;
+      } else
+        ret = regnode(ANYOF);
+      if (*regparse == ']' || *regparse == '-')
+        regc(*regparse++);
+      while (*regparse != '\0' && *regparse != ']') {
+        if (*regparse == '-') {
+          regparse++;
+          if (*regparse == ']' || *regparse == '\0')
+            regc('-');
+          else {
+            rxpclass = UCHARAT(regparse - 2) + 1;
+            rxpclassend = UCHARAT(regparse);
+            if (rxpclass > rxpclassend + 1) {
+              // RAISE Error, SYM(RegularExpression), SYM(Invalid_Range),
+              printf("RegularExpression::compile(): Invalid range in [].\n");
+              return 0;
+            }
+            for (; rxpclass <= rxpclassend; rxpclass++)
+              regc(static_cast<char>(rxpclass));
+            regparse++;
+          }
+        } else
+          regc(*regparse++);
+      }
+      regc('\0');
+      if (*regparse != ']') {
+        // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket),
+        printf("RegularExpression::compile(): Unmatched [].\n");
+        return 0;
+      }
+      regparse++;
+      *flagp |= HASWIDTH | SIMPLE;
+    } break;
+    case '(':
+      ret = reg(1, &flags);
+      if (ret == 0)
+        return (0);
+      *flagp |= flags & (HASWIDTH | SPSTART);
+      break;
+    case '\0':
+    case '|':
+    case ')':
+      // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+      printf("RegularExpression::compile(): Internal error.\n"); // Never here
+      return 0;
+    case '?':
+    case '+':
+    case '*':
+      // RAISE Error, SYM(RegularExpression), SYM(No_Operand),
+      printf("RegularExpression::compile(): ?+* follows nothing.\n");
+      return 0;
+    case '\\':
+      if (*regparse == '\0') {
+        // RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash),
+        printf("RegularExpression::compile(): Trailing backslash.\n");
+        return 0;
+      }
+      ret = regnode(EXACTLY);
+      regc(*regparse++);
+      regc('\0');
+      *flagp |= HASWIDTH | SIMPLE;
+      break;
+    default: {
+      int len;
+      char ender;
+
+      regparse--;
+      len = int(strcspn(regparse, META));
+      if (len <= 0) {
+        // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+        printf("RegularExpression::compile(): Internal error.\n");
+        return 0;
+      }
+      ender = *(regparse + len);
+      if (len > 1 && ISMULT(ender))
+        len--; // Back off clear of ?+* operand.
+      *flagp |= HASWIDTH;
+      if (len == 1)
+        *flagp |= SIMPLE;
+      ret = regnode(EXACTLY);
+      while (len > 0) {
+        regc(*regparse++);
+        len--;
+      }
+      regc('\0');
+    } break;
+  }
+  return (ret);
+}
+
+/*
+ - regnode - emit a node
+   Location.
+ */
+static char* regnode(char op)
+{
+  char* ret;
+  char* ptr;
+
+  ret = regcode;
+  if (ret == &regdummy) {
+    regsize += 3;
+    return (ret);
+  }
+
+  ptr = ret;
+  *ptr++ = op;
+  *ptr++ = '\0'; // Null "next" pointer.
+  *ptr++ = '\0';
+  regcode = ptr;
+
+  return (ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void regc(char b)
+{
+  if (regcode != &regdummy)
+    *regcode++ = b;
+  else
+    regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void reginsert(char op, char* opnd)
+{
+  char* src;
+  char* dst;
+  char* place;
+
+  if (regcode == &regdummy) {
+    regsize += 3;
+    return;
+  }
+
+  src = regcode;
+  regcode += 3;
+  dst = regcode;
+  while (src > opnd)
+    *--dst = *--src;
+
+  place = opnd; // Op node, where operand used to be.
+  *place++ = op;
+  *place++ = '\0';
+  *place = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void regtail(char* p, const char* val)
+{
+  char* scan;
+  char* temp;
+  int offset;
+
+  if (p == &regdummy)
+    return;
+
+  // Find last node.
+  scan = p;
+  for (;;) {
+    temp = regnext(scan);
+    if (temp == 0)
+      break;
+    scan = temp;
+  }
+
+  if (OP(scan) == BACK)
+    offset = int(scan - val);
+  else
+    offset = int(val - scan);
+  *(scan + 1) = static_cast<char>((offset >> 8) & 0377);
+  *(scan + 2) = static_cast<char>(offset & 0377);
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void regoptail(char* p, const char* val)
+{
+  // "Operandless" and "op != BRANCH" are synonymous in practice.
+  if (p == 0 || p == &regdummy || OP(p) != BRANCH)
+    return;
+  regtail(OPERAND(p), val);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+//  find and friends
+//
+////////////////////////////////////////////////////////////////////////
+
+/*
+ * Global work variables for find().
+ */
+static const char* reginput;   // String-input pointer.
+static const char* regbol;     // Beginning of input, for ^ check.
+static const char** regstartp; // Pointer to startp array.
+static const char** regendp;   // Ditto for endp.
+
+/*
+ * Forwards.
+ */
+static int regtry(const char*, const char**, const char**, const char*);
+static int regmatch(const char*);
+static int regrepeat(const char*);
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+static char* regprop();
+#endif
+
+// find -- Matches the regular expression to the given string.
+// Returns true if found, and sets start and end indexes accordingly.
+
+bool RegularExpression::find(const char* string)
+{
+  const char* s;
+
+  this->searchstring = string;
+
+  if (!this->program) {
+    return false;
+  }
+
+  // Check validity of program.
+  if (UCHARAT(this->program) != MAGIC) {
+    // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+    printf(
+      "RegularExpression::find(): Compiled regular expression corrupted.\n");
+    return 0;
+  }
+
+  // If there is a "must appear" string, look for it.
+  if (this->regmust != 0) {
+    s = string;
+    while ((s = strchr(s, this->regmust[0])) != 0) {
+      if (strncmp(s, this->regmust, this->regmlen) == 0)
+        break; // Found it.
+      s++;
+    }
+    if (s == 0) // Not present.
+      return (0);
+  }
+
+  // Mark beginning of line for ^ .
+  regbol = string;
+
+  // Simplest case:  anchored match need be tried only once.
+  if (this->reganch)
+    return (regtry(string, this->startp, this->endp, this->program) != 0);
+
+  // Messy cases:  unanchored match.
+  s = string;
+  if (this->regstart != '\0')
+    // We know what char it must start with.
+    while ((s = strchr(s, this->regstart)) != 0) {
+      if (regtry(s, this->startp, this->endp, this->program))
+        return (1);
+      s++;
+    }
+  else
+    // We don't -- general case.
+    do {
+      if (regtry(s, this->startp, this->endp, this->program))
+        return (1);
+    } while (*s++ != '\0');
+
+  // Failure.
+  return (0);
+}
+
+/*
+ - regtry - try match at specific point
+   0 failure, 1 success
+ */
+static int regtry(const char* string, const char** start, const char** end,
+                  const char* prog)
+{
+  int i;
+  const char** sp1;
+  const char** ep;
+
+  reginput = string;
+  regstartp = start;
+  regendp = end;
+
+  sp1 = start;
+  ep = end;
+  for (i = RegularExpression::NSUBEXP; i > 0; i--) {
+    *sp1++ = 0;
+    *ep++ = 0;
+  }
+  if (regmatch(prog + 1)) {
+    start[0] = string;
+    end[0] = reginput;
+    return (1);
+  } else
+    return (0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple:  check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly.  In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ * 0 failure, 1 success
+ */
+static int regmatch(const char* prog)
+{
+  const char* scan; // Current node.
+  const char* next; // Next node.
+
+  scan = prog;
+
+  while (scan != 0) {
+
+    next = regnext(scan);
+
+    switch (OP(scan)) {
+      case BOL:
+        if (reginput != regbol)
+          return (0);
+        break;
+      case EOL:
+        if (*reginput != '\0')
+          return (0);
+        break;
+      case ANY:
+        if (*reginput == '\0')
+          return (0);
+        reginput++;
+        break;
+      case EXACTLY: {
+        size_t len;
+        const char* opnd;
+
+        opnd = OPERAND(scan);
+        // Inline the first character, for speed.
+        if (*opnd != *reginput)
+          return (0);
+        len = strlen(opnd);
+        if (len > 1 && strncmp(opnd, reginput, len) != 0)
+          return (0);
+        reginput += len;
+      } break;
+      case ANYOF:
+        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == 0)
+          return (0);
+        reginput++;
+        break;
+      case ANYBUT:
+        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != 0)
+          return (0);
+        reginput++;
+        break;
+      case NOTHING:
+        break;
+      case BACK:
+        break;
+      case OPEN + 1:
+      case OPEN + 2:
+      case OPEN + 3:
+      case OPEN + 4:
+      case OPEN + 5:
+      case OPEN + 6:
+      case OPEN + 7:
+      case OPEN + 8:
+      case OPEN + 9: {
+        int no;
+        const char* save;
+
+        no = OP(scan) - OPEN;
+        save = reginput;
+
+        if (regmatch(next)) {
+
+          //
+          // Don't set startp if some later invocation of the
+          // same parentheses already has.
+          //
+          if (regstartp[no] == 0)
+            regstartp[no] = save;
+          return (1);
+        } else
+          return (0);
+      }
+      //              break;
+      case CLOSE + 1:
+      case CLOSE + 2:
+      case CLOSE + 3:
+      case CLOSE + 4:
+      case CLOSE + 5:
+      case CLOSE + 6:
+      case CLOSE + 7:
+      case CLOSE + 8:
+      case CLOSE + 9: {
+        int no;
+        const char* save;
+
+        no = OP(scan) - CLOSE;
+        save = reginput;
+
+        if (regmatch(next)) {
+
+          //
+          // Don't set endp if some later invocation of the
+          // same parentheses already has.
+          //
+          if (regendp[no] == 0)
+            regendp[no] = save;
+          return (1);
+        } else
+          return (0);
+      }
+      //              break;
+      case BRANCH: {
+
+        const char* save;
+
+        if (OP(next) != BRANCH) // No choice.
+          next = OPERAND(scan); // Avoid recursion.
+        else {
+          do {
+            save = reginput;
+            if (regmatch(OPERAND(scan)))
+              return (1);
+            reginput = save;
+            scan = regnext(scan);
+          } while (scan != 0 && OP(scan) == BRANCH);
+          return (0);
+          // NOTREACHED
+        }
+      } break;
+      case STAR:
+      case PLUS: {
+        char nextch;
+        int no;
+        const char* save;
+        int min_no;
+
+        //
+        // Lookahead to avoid useless match attempts when we know
+        // what character comes next.
+        //
+        nextch = '\0';
+        if (OP(next) == EXACTLY)
+          nextch = *OPERAND(next);
+        min_no = (OP(scan) == STAR) ? 0 : 1;
+        save = reginput;
+        no = regrepeat(OPERAND(scan));
+        while (no >= min_no) {
+          // If it could work, try it.
+          if (nextch == '\0' || *reginput == nextch)
+            if (regmatch(next))
+              return (1);
+          // Couldn't or didn't -- back up.
+          no--;
+          reginput = save + no;
+        }
+        return (0);
+      }
+      //              break;
+      case END:
+        return (1); // Success!
+
+      default:
+        // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+        printf(
+          "RegularExpression::find(): Internal error -- memory corrupted.\n");
+        return 0;
+    }
+    scan = next;
+  }
+
+  //
+  //  We get here only if there's trouble -- normally "case END" is the
+  //  terminating point.
+  //
+  // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+  printf("RegularExpression::find(): Internal error -- corrupted pointers.\n");
+  return (0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int regrepeat(const char* p)
+{
+  int count = 0;
+  const char* scan;
+  const char* opnd;
+
+  scan = reginput;
+  opnd = OPERAND(p);
+  switch (OP(p)) {
+    case ANY:
+      count = int(strlen(scan));
+      scan += count;
+      break;
+    case EXACTLY:
+      while (*opnd == *scan) {
+        count++;
+        scan++;
+      }
+      break;
+    case ANYOF:
+      while (*scan != '\0' && strchr(opnd, *scan) != 0) {
+        count++;
+        scan++;
+      }
+      break;
+    case ANYBUT:
+      while (*scan != '\0' && strchr(opnd, *scan) == 0) {
+        count++;
+        scan++;
+      }
+      break;
+    default: // Oh dear.  Called inappropriately.
+      // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+      printf("cm RegularExpression::find(): Internal error.\n");
+      return 0;
+  }
+  reginput = scan;
+  return (count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static const char* regnext(const char* p)
+{
+  int offset;
+
+  if (p == &regdummy)
+    return (0);
+
+  offset = NEXT(p);
+  if (offset == 0)
+    return (0);
+
+  if (OP(p) == BACK)
+    return (p - offset);
+  else
+    return (p + offset);
+}
+
+static char* regnext(char* p)
+{
+  int offset;
+
+  if (p == &regdummy)
+    return (0);
+
+  offset = NEXT(p);
+  if (offset == 0)
+    return (0);
+
+  if (OP(p) == BACK)
+    return (p - offset);
+  else
+    return (p + offset);
+}
+
+} // namespace KWSYS_NAMESPACE
diff --git a/thirdparty/KWSys/adios2sys/RegularExpression.hxx.in b/thirdparty/KWSys/adios2sys/RegularExpression.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..606e3da6ecf040d2de45a59f5c46f873c10bb358
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/RegularExpression.hxx.in
@@ -0,0 +1,425 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+// Original Copyright notice:
+// Copyright (C) 1991 Texas Instruments Incorporated.
+//
+// Permission is granted to any individual or institution to use, copy, modify,
+// and distribute this software, provided that this complete copyright and
+// permission notice is maintained, intact, in all copies and supporting
+// documentation.
+//
+// Texas Instruments Incorporated provides this software "as is" without
+// express or implied warranty.
+//
+// Created: MNF 06/13/89  Initial Design and Implementation
+// Updated: LGO 08/09/89  Inherit from Generic
+// Updated: MBN 09/07/89  Added conditional exception handling
+// Updated: MBN 12/15/89  Sprinkled "const" qualifiers all over the place!
+// Updated: DLS 03/22/91  New lite version
+//
+
+#ifndef @KWSYS_NAMESPACE@_RegularExpression_hxx
+#define @KWSYS_NAMESPACE@_RegularExpression_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+
+/* Disable useless Borland warnings.  KWSys tries not to force things
+   on its includers, but there is no choice here.  */
+#if defined(__BORLANDC__)
+#pragma warn - 8027 /* function not inlined.  */
+#endif
+
+namespace @KWSYS_NAMESPACE@ {
+
+/** \class RegularExpression
+ * \brief Implements pattern matching with regular expressions.
+ *
+ * This is the header file for the regular expression class.  An object of
+ * this class contains a regular expression, in a special "compiled" format.
+ * This compiled format consists of several slots all kept as the objects
+ * private data.  The RegularExpression class provides a convenient way to
+ * represent regular expressions.  It makes it easy to search for the same
+ * regular expression in many different strings without having to compile a
+ * string to regular expression format more than necessary.
+ *
+ * This class implements pattern matching via regular expressions.
+ * A regular expression allows a programmer to specify  complex
+ * patterns  that  can  be searched for and matched against the
+ * character string of a string object. In its simplest form, a
+ * regular  expression  is  a  sequence  of  characters used to
+ * search for exact character matches. However, many times  the
+ * exact  sequence to be found is not known, or only a match at
+ * the beginning or end of a string is desired. The RegularExpression regu-
+ * lar  expression  class implements regular expression pattern
+ * matching as is found and implemented in many  UNIX  commands
+ * and utilities.
+ *
+ * Example: The perl code
+ *
+ *    $filename =~ m"([a-z]+)\.cc";
+ *    print $1;
+ *
+ * Is written as follows in C++
+ *
+ *    RegularExpression re("([a-z]+)\\.cc");
+ *    re.find(filename);
+ *    cerr << re.match(1);
+ *
+ *
+ * The regular expression class provides a convenient mechanism
+ * for  specifying  and  manipulating  regular expressions. The
+ * regular expression object allows specification of such  pat-
+ * terns  by using the following regular expression metacharac-
+ * ters:
+ *
+ *  ^        Matches at beginning of a line
+ *
+ *  $        Matches at end of a line
+ *
+ * .         Matches any single character
+ *
+ * [ ]       Matches any character(s) inside the brackets
+ *
+ * [^ ]      Matches any character(s) not inside the brackets
+ *
+ *  -        Matches any character in range on either side of a dash
+ *
+ *  *        Matches preceding pattern zero or more times
+ *
+ *  +        Matches preceding pattern one or more times
+ *
+ *  ?        Matches preceding pattern zero or once only
+ *
+ * ()        Saves a matched expression and uses it in a  later match
+ *
+ * Note that more than one of these metacharacters can be  used
+ * in  a  single  regular expression in order to create complex
+ * search patterns. For example, the pattern [^ab1-9]  says  to
+ * match  any  character  sequence that does not begin with the
+ * characters "ab"  followed  by  numbers  in  the  series  one
+ * through nine.
+ *
+ * There are three constructors for RegularExpression.  One just creates an
+ * empty RegularExpression object.  Another creates a RegularExpression
+ * object and initializes it with a regular expression that is given in the
+ * form of a char*.  The third takes a reference to a RegularExpression
+ * object as an argument and creates an object initialized with the
+ * information from the given RegularExpression object.
+ *
+ * The  find  member function  finds   the  first  occurence   of  the regualr
+ * expression of that object in the string given to find as an argument.  Find
+ * returns a boolean, and  if true,  mutates  the private  data appropriately.
+ * Find sets pointers to the beginning and end of  the thing last  found, they
+ * are pointers into the actual string  that was searched.   The start and end
+ * member functions return indicies  into the searched string that  correspond
+ * to the beginning   and  end pointers  respectively.   The    compile member
+ * function takes a char* and puts the  compiled version of the char* argument
+ * into the object's private data fields.  The == and  != operators only check
+ * the  to see  if   the compiled  regular  expression   is the same, and  the
+ * deep_equal functions also checks  to see if the  start and end pointers are
+ * the same.  The is_valid  function returns false if  program is set to NULL,
+ * (i.e. there is no valid compiled exression).  The set_invalid function sets
+ * the  program to NULL  (Warning: this deletes the compiled  expression). The
+ * following examples may help clarify regular expression usage:
+ *
+ *   *  The regular expression  "^hello" matches  a "hello"  only at  the
+ *      beginning of a  line.  It would match "hello  there" but not "hi,
+ *      hello there".
+ *
+ *   *  The regular expression "long$" matches a  "long"  only at the end
+ *      of a line. It would match "so long\0", but not "long ago".
+ *
+ *   *  The regular expression "t..t..g"  will match anything that  has a
+ *      "t" then any two characters, another "t", any  two characters and
+ *      then a "g".   It will match  "testing", or "test again" but would
+ *      not match "toasting"
+ *
+ *   *  The regular  expression "[1-9ab]" matches any  number one through
+ *      nine, and the characters  "a" and  "b".  It would match "hello 1"
+ *      or "begin", but would not match "no-match".
+ *
+ *   *  The  regular expression "[^1-9ab]"  matches any character that is
+ *      not a number one  through nine, or  an "a" or "b".   It would NOT
+ *      match "hello 1" or "begin", but would match "no-match".
+ *
+ *   *  The regular expression "br* " matches  something that begins with
+ *      a "b", is followed by zero or more "r"s, and ends in a space.  It
+ *      would match "brrrrr ", and "b ", but would not match "brrh ".
+ *
+ *   *  The regular expression "br+ " matches something  that begins with
+ *      a "b", is followed by one or more "r"s, and ends in  a space.  It
+ *      would match "brrrrr ",  and  "br ", but would not  match "b  " or
+ *      "brrh ".
+ *
+ *   *  The regular expression "br? " matches  something that begins with
+ *      a "b", is followed by zero or one "r"s, and ends in  a space.  It
+ *      would  match  "br ", and "b  ", but would not match  "brrrr "  or
+ *      "brrh ".
+ *
+ *   *  The regular expression "(..p)b" matches  something ending with pb
+ *      and beginning with whatever the two characters before the first p
+ *      encounterd in the line were.  It would find  "repb" in "rep drepa
+ *      qrepb".  The regular expression "(..p)a"  would find "repa qrepb"
+ *      in "rep drepa qrepb"
+ *
+ *   *  The regular expression "d(..p)" matches something ending  with p,
+ *      beginning with d, and having  two characters  in between that are
+ *      the same as the two characters before  the first p  encounterd in
+ *      the line.  It would match "drepa qrepb" in "rep drepa qrepb".
+ *
+ */
+class @KWSYS_NAMESPACE@_EXPORT RegularExpression
+{
+public:
+  /**
+   * Instantiate RegularExpression with program=NULL.
+   */
+  inline RegularExpression();
+
+  /**
+   * Instantiate RegularExpression with compiled char*.
+   */
+  inline RegularExpression(char const*);
+
+  /**
+   * Instantiate RegularExpression as a copy of another regular expression.
+   */
+  RegularExpression(RegularExpression const&);
+
+  /**
+   * Instantiate RegularExpression with compiled string.
+   */
+  inline RegularExpression(std::string const&);
+
+  /**
+   * Destructor.
+   */
+  inline ~RegularExpression();
+
+  /**
+   * Compile a regular expression into internal code
+   * for later pattern matching.
+   */
+  bool compile(char const*);
+
+  /**
+   * Compile a regular expression into internal code
+   * for later pattern matching.
+   */
+  inline bool compile(std::string const&);
+
+  /**
+   * Matches the regular expression to the given string.
+   * Returns true if found, and sets start and end indexes accordingly.
+   */
+  bool find(char const*);
+
+  /**
+   * Matches the regular expression to the given std string.
+   * Returns true if found, and sets start and end indexes accordingly.
+   */
+  inline bool find(std::string const&);
+
+  /**
+   * Index to start of first find.
+   */
+  inline std::string::size_type start() const;
+
+  /**
+   * Index to end of first find.
+   */
+  inline std::string::size_type end() const;
+
+  /**
+   * Copy the given regular expression.
+   */
+  RegularExpression& operator=(const RegularExpression& rxp);
+
+  /**
+   * Returns true if two regular expressions have the same
+   * compiled program for pattern matching.
+   */
+  bool operator==(RegularExpression const&) const;
+
+  /**
+   * Returns true if two regular expressions have different
+   * compiled program for pattern matching.
+   */
+  inline bool operator!=(RegularExpression const&) const;
+
+  /**
+   * Returns true if have the same compiled regular expressions
+   * and the same start and end pointers.
+   */
+  bool deep_equal(RegularExpression const&) const;
+
+  /**
+   * True if the compiled regexp is valid.
+   */
+  inline bool is_valid() const;
+
+  /**
+   * Marks the regular expression as invalid.
+   */
+  inline void set_invalid();
+
+  /**
+   * Destructor.
+   */
+  // awf added
+  std::string::size_type start(int n) const;
+  std::string::size_type end(int n) const;
+  std::string match(int n) const;
+
+  enum
+  {
+    NSUBEXP = 10
+  };
+
+private:
+  const char* startp[NSUBEXP];
+  const char* endp[NSUBEXP];
+  char regstart;                  // Internal use only
+  char reganch;                   // Internal use only
+  const char* regmust;            // Internal use only
+  std::string::size_type regmlen; // Internal use only
+  char* program;
+  int progsize;
+  const char* searchstring;
+};
+
+/**
+ * Create an empty regular expression.
+ */
+inline RegularExpression::RegularExpression()
+{
+  this->program = 0;
+}
+
+/**
+ * Creates a regular expression from string s, and
+ * compiles s.
+ */
+inline RegularExpression::RegularExpression(const char* s)
+{
+  this->program = 0;
+  if (s) {
+    this->compile(s);
+  }
+}
+
+/**
+ * Creates a regular expression from string s, and
+ * compiles s.
+ */
+inline RegularExpression::RegularExpression(const std::string& s)
+{
+  this->program = 0;
+  this->compile(s);
+}
+
+/**
+ * Destroys and frees space allocated for the regular expression.
+ */
+inline RegularExpression::~RegularExpression()
+{
+  //#ifndef _WIN32
+  delete[] this->program;
+  //#endif
+}
+
+/**
+ * Compile a regular expression into internal code
+ * for later pattern matching.
+ */
+inline bool RegularExpression::compile(std::string const& s)
+{
+  return this->compile(s.c_str());
+}
+
+/**
+ * Matches the regular expression to the given std string.
+ * Returns true if found, and sets start and end indexes accordingly.
+ */
+inline bool RegularExpression::find(std::string const& s)
+{
+  return this->find(s.c_str());
+}
+
+/**
+ * Set the start position for the regular expression.
+ */
+inline std::string::size_type RegularExpression::start() const
+{
+  return static_cast<std::string::size_type>(this->startp[0] - searchstring);
+}
+
+/**
+ * Returns the start/end index of the last item found.
+ */
+inline std::string::size_type RegularExpression::end() const
+{
+  return static_cast<std::string::size_type>(this->endp[0] - searchstring);
+}
+
+/**
+ * Returns true if two regular expressions have different
+ * compiled program for pattern matching.
+ */
+inline bool RegularExpression::operator!=(const RegularExpression& r) const
+{
+  return (!(*this == r));
+}
+
+/**
+ * Returns true if a valid regular expression is compiled
+ * and ready for pattern matching.
+ */
+inline bool RegularExpression::is_valid() const
+{
+  return (this->program != 0);
+}
+
+inline void RegularExpression::set_invalid()
+{
+  //#ifndef _WIN32
+  delete[] this->program;
+  //#endif
+  this->program = 0;
+}
+
+/**
+ * Return start index of nth submatch. start(0) is the start of the full match.
+ */
+inline std::string::size_type RegularExpression::start(int n) const
+{
+  return static_cast<std::string::size_type>(this->startp[n] - searchstring);
+}
+
+/**
+ * Return end index of nth submatch. end(0) is the end of the full match.
+ */
+inline std::string::size_type RegularExpression::end(int n) const
+{
+  return static_cast<std::string::size_type>(this->endp[n] - searchstring);
+}
+
+/**
+ * Return nth submatch as a string.
+ */
+inline std::string RegularExpression::match(int n) const
+{
+  if (this->startp[n] == 0) {
+    return std::string("");
+  } else {
+    return std::string(this->startp[n], static_cast<std::string::size_type>(
+                                          this->endp[n] - this->startp[n]));
+  }
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/SharedForward.h.in b/thirdparty/KWSys/adios2sys/SharedForward.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..c9ae135529812c2f7b05330d6f5c0335a0d91b33
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/SharedForward.h.in
@@ -0,0 +1,894 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_SharedForward_h
+#define @KWSYS_NAMESPACE@_SharedForward_h
+
+/*
+  This header is used to create a forwarding executable sets up the
+  shared library search path and replaces itself with a real
+  executable.  This is useful when creating installations on UNIX with
+  shared libraries that will run from any install directory.  Typical
+  usage:
+
+  #if defined(CMAKE_INTDIR)
+  # define CONFIG_DIR_PRE CMAKE_INTDIR "/"
+  # define CONFIG_DIR_POST "/" CMAKE_INTDIR
+  #else
+  # define CONFIG_DIR_PRE ""
+  # define CONFIG_DIR_POST ""
+  #endif
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "/path/to/foo-build/bin"
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL "../lib/foo-1.2"
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD CONFIG_DIR_PRE "foo-real"
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL
+  "../lib/foo-1.2/foo-real"
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command"
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print"
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd"
+  #if defined(CMAKE_INTDIR)
+  # define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR
+  #endif
+  #include <@KWSYS_NAMESPACE@/SharedForward.h>
+  int main(int argc, char** argv)
+  {
+    return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv);
+  }
+
+  Specify search and executable paths relative to the forwarding
+  executable location or as full paths.  Include no trailing slash.
+  In the case of a multi-configuration build, when CMAKE_INTDIR is
+  defined, the DIR_BUILD setting should point at the directory above
+  the executable (the one containing the per-configuration
+  subdirectory specified by CMAKE_INTDIR).  Then PATH_BUILD entries
+  and EXE_BUILD should be specified relative to this location and use
+  CMAKE_INTDIR as necessary.  In the above example imagine appending
+  the PATH_BUILD or EXE_BUILD setting to the DIR_BUILD setting.  The
+  result should form a valid path with per-configuration subdirectory.
+
+  Additional paths may be specified in the PATH_BUILD and PATH_INSTALL
+  variables by using comma-separated strings.    For example:
+
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD \
+          "." CONFIG_DIR_POST, "/path/to/bar-build" CONFIG_DIR_POST
+  #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL \
+          "../lib/foo-1.2", "../lib/bar-4.5"
+
+  See the comments below for specific explanations of each macro.
+*/
+
+/* Disable -Wcast-qual warnings since they are too hard to fix in a
+   cross-platform way.  */
+#if defined(__clang__) && defined(__has_warning)
+#if __has_warning("-Wcast-qual")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wcast-qual"
+#endif
+#endif
+
+#if defined(__BORLANDC__) && !defined(__cplusplus)
+/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an
+   unused parameter using "(param)" syntax (i.e. no cast to void).  */
+#pragma warn - 8019
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+/* Full path to the directory in which this executable is built.  Do
+   not include a trailing slash.  */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD)
+#error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_DIR_BUILD)
+#define KWSYS_SHARED_FORWARD_DIR_BUILD                                        \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD
+#endif
+
+/* Library search path for build tree.  */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD)
+#error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_PATH_BUILD)
+#define KWSYS_SHARED_FORWARD_PATH_BUILD                                       \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD
+#endif
+
+/* Library search path for install tree.  */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL)
+#error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_PATH_INSTALL)
+#define KWSYS_SHARED_FORWARD_PATH_INSTALL                                     \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL
+#endif
+
+/* The real executable to which to forward in the build tree.  */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD)
+#error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_EXE_BUILD)
+#define KWSYS_SHARED_FORWARD_EXE_BUILD                                        \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD
+#endif
+
+/* The real executable to which to forward in the install tree.  */
+#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL)
+#error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL"
+#endif
+#if !defined(KWSYS_SHARED_FORWARD_EXE_INSTALL)
+#define KWSYS_SHARED_FORWARD_EXE_INSTALL                                      \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL
+#endif
+
+/* The configuration name with which this executable was built (Debug/Release).
+ */
+#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME)
+#define KWSYS_SHARED_FORWARD_CONFIG_NAME                                      \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME
+#else
+#undef KWSYS_SHARED_FORWARD_CONFIG_NAME
+#endif
+
+/* Create command line option to replace executable.  */
+#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND)
+#if !defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND)
+#define KWSYS_SHARED_FORWARD_OPTION_COMMAND                                   \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND
+#endif
+#else
+#undef KWSYS_SHARED_FORWARD_OPTION_COMMAND
+#endif
+
+/* Create command line option to print environment setting and exit.  */
+#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT)
+#if !defined(KWSYS_SHARED_FORWARD_OPTION_PRINT)
+#define KWSYS_SHARED_FORWARD_OPTION_PRINT                                     \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT
+#endif
+#else
+#undef KWSYS_SHARED_FORWARD_OPTION_PRINT
+#endif
+
+/* Create command line option to run ldd or equivalent.  */
+#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD)
+#if !defined(KWSYS_SHARED_FORWARD_OPTION_LDD)
+#define KWSYS_SHARED_FORWARD_OPTION_LDD                                       \
+  @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD
+#endif
+#else
+#undef KWSYS_SHARED_FORWARD_OPTION_LDD
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Include needed system headers.  */
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h> /* size_t */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+
+#include <io.h>
+#include <process.h>
+#define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */
+#else
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Configuration for this platform.  */
+
+/* The path separator for this platform.  */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define KWSYS_SHARED_FORWARD_PATH_SEP ';'
+#define KWSYS_SHARED_FORWARD_PATH_SLASH '\\'
+#else
+#define KWSYS_SHARED_FORWARD_PATH_SEP ':'
+#define KWSYS_SHARED_FORWARD_PATH_SLASH '/'
+#endif
+static const char kwsys_shared_forward_path_sep[2] = {
+  KWSYS_SHARED_FORWARD_PATH_SEP, 0
+};
+static const char kwsys_shared_forward_path_slash[2] = {
+  KWSYS_SHARED_FORWARD_PATH_SLASH, 0
+};
+
+/* The maximum length of a file name.  */
+#if defined(PATH_MAX)
+#define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX
+#elif defined(MAXPATHLEN)
+#define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN
+#else
+#define KWSYS_SHARED_FORWARD_MAXPATH 16384
+#endif
+
+/* Select the environment variable holding the shared library runtime
+   search path for this platform and build configuration.  Also select
+   ldd command equivalent.  */
+
+/* Linux */
+#if defined(__linux)
+#define KWSYS_SHARED_FORWARD_LDD "ldd"
+#define KWSYS_SHARED_FORWARD_LDD_N 1
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+
+/* FreeBSD */
+#elif defined(__FreeBSD__)
+#define KWSYS_SHARED_FORWARD_LDD "ldd"
+#define KWSYS_SHARED_FORWARD_LDD_N 1
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+
+/* OpenBSD */
+#elif defined(__OpenBSD__)
+#define KWSYS_SHARED_FORWARD_LDD "ldd"
+#define KWSYS_SHARED_FORWARD_LDD_N 1
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+
+/* OSX */
+#elif defined(__APPLE__)
+#define KWSYS_SHARED_FORWARD_LDD "otool", "-L"
+#define KWSYS_SHARED_FORWARD_LDD_N 2
+#define KWSYS_SHARED_FORWARD_LDPATH "DYLD_LIBRARY_PATH"
+
+/* AIX */
+#elif defined(_AIX)
+#define KWSYS_SHARED_FORWARD_LDD "dump", "-H"
+#define KWSYS_SHARED_FORWARD_LDD_N 2
+#define KWSYS_SHARED_FORWARD_LDPATH "LIBPATH"
+
+/* SUN */
+#elif defined(__sun)
+#define KWSYS_SHARED_FORWARD_LDD "ldd"
+#define KWSYS_SHARED_FORWARD_LDD_N 1
+#include <sys/isa_defs.h>
+#if defined(_ILP32)
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+#elif defined(_LP64)
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64"
+#endif
+
+/* HP-UX */
+#elif defined(__hpux)
+#define KWSYS_SHARED_FORWARD_LDD "chatr"
+#define KWSYS_SHARED_FORWARD_LDD_N 1
+#if defined(__LP64__)
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+#else
+#define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH"
+#endif
+
+/* SGI MIPS */
+#elif defined(__sgi) && defined(_MIPS_SIM)
+#define KWSYS_SHARED_FORWARD_LDD "ldd"
+#define KWSYS_SHARED_FORWARD_LDD_N 1
+#if _MIPS_SIM == _ABIO32
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+#elif _MIPS_SIM == _ABIN32
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH"
+#elif _MIPS_SIM == _ABI64
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH"
+#endif
+
+/* Cygwin */
+#elif defined(__CYGWIN__)
+#define KWSYS_SHARED_FORWARD_LDD "cygcheck" /* TODO: cygwin 1.7 has ldd */
+#define KWSYS_SHARED_FORWARD_LDD_N 1
+#define KWSYS_SHARED_FORWARD_LDPATH "PATH"
+
+/* Windows */
+#elif defined(_WIN32)
+#define KWSYS_SHARED_FORWARD_LDPATH "PATH"
+
+/* Guess on this unknown system.  */
+#else
+#define KWSYS_SHARED_FORWARD_LDD "ldd"
+#define KWSYS_SHARED_FORWARD_LDD_N 1
+#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
+#endif
+
+#ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV
+/*--------------------------------------------------------------------------*/
+typedef struct kwsys_sf_arg_info_s
+{
+  const char* arg;
+  int size;
+  int quote;
+} kwsys_sf_arg_info;
+
+/*--------------------------------------------------------------------------*/
+static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in)
+{
+  /* Initialize information.  */
+  kwsys_sf_arg_info info;
+
+  /* String iterator.  */
+  const char* c;
+
+  /* Keep track of how many backslashes have been encountered in a row.  */
+  int windows_backslashes = 0;
+
+  /* Start with the length of the original argument, plus one for
+     either a terminating null or a separating space.  */
+  info.arg = in;
+  info.size = (int)strlen(in) + 1;
+  info.quote = 0;
+
+  /* Scan the string for characters that require escaping or quoting.  */
+  for (c = in; *c; ++c) {
+    /* Check whether this character needs quotes.  */
+    if (strchr(" \t?'#&<>|^", *c)) {
+      info.quote = 1;
+    }
+
+    /* On Windows only backslashes and double-quotes need escaping.  */
+    if (*c == '\\') {
+      /* Found a backslash.  It may need to be escaped later.  */
+      ++windows_backslashes;
+    } else if (*c == '"') {
+      /* Found a double-quote.  We need to escape it and all
+         immediately preceding backslashes.  */
+      info.size += windows_backslashes + 1;
+      windows_backslashes = 0;
+    } else {
+      /* Found another character.  This eliminates the possibility
+         that any immediately preceding backslashes will be
+         escaped.  */
+      windows_backslashes = 0;
+    }
+  }
+
+  /* Check whether the argument needs surrounding quotes.  */
+  if (info.quote) {
+    /* Surrounding quotes are needed.  Allocate space for them.  */
+    info.size += 2;
+
+    /* We must escape all ending backslashes when quoting on windows.  */
+    info.size += windows_backslashes;
+  }
+
+  return info;
+}
+
+/*--------------------------------------------------------------------------*/
+static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out)
+{
+  /* String iterator.  */
+  const char* c;
+
+  /* Keep track of how many backslashes have been encountered in a row.  */
+  int windows_backslashes = 0;
+
+  /* Whether the argument must be quoted.  */
+  if (info.quote) {
+    /* Add the opening quote for this argument.  */
+    *out++ = '"';
+  }
+
+  /* Scan the string for characters that require escaping or quoting.  */
+  for (c = info.arg; *c; ++c) {
+    /* On Windows only backslashes and double-quotes need escaping.  */
+    if (*c == '\\') {
+      /* Found a backslash.  It may need to be escaped later.  */
+      ++windows_backslashes;
+    } else if (*c == '"') {
+      /* Found a double-quote.  Escape all immediately preceding
+         backslashes.  */
+      while (windows_backslashes > 0) {
+        --windows_backslashes;
+        *out++ = '\\';
+      }
+
+      /* Add the backslash to escape the double-quote.  */
+      *out++ = '\\';
+    } else {
+      /* We encountered a normal character.  This eliminates any
+         escaping needed for preceding backslashes.  */
+      windows_backslashes = 0;
+    }
+
+    /* Store this character.  */
+    *out++ = *c;
+  }
+
+  if (info.quote) {
+    /* Add enough backslashes to escape any trailing ones.  */
+    while (windows_backslashes > 0) {
+      --windows_backslashes;
+      *out++ = '\\';
+    }
+
+    /* Add the closing quote for this argument.  */
+    *out++ = '"';
+  }
+
+  /* Store a terminating null without incrementing.  */
+  *out = 0;
+
+  return out;
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Function to convert a logical or relative path to a physical full path.  */
+static int kwsys_shared_forward_realpath(const char* in_path, char* out_path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  /* Implementation for Windows.  */
+  DWORD n =
+    GetFullPathNameA(in_path, KWSYS_SHARED_FORWARD_MAXPATH, out_path, 0);
+  return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH;
+#else
+  /* Implementation for UNIX.  */
+  return realpath(in_path, out_path) != 0;
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsys_shared_forward_samepath(const char* file1, const char* file2)
+{
+#if defined(_WIN32)
+  int result = 0;
+  HANDLE h1 = CreateFileA(file1, GENERIC_READ, FILE_SHARE_READ, NULL,
+                          OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  HANDLE h2 = CreateFileA(file2, GENERIC_READ, FILE_SHARE_READ, NULL,
+                          OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if (h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE) {
+    BY_HANDLE_FILE_INFORMATION fi1;
+    BY_HANDLE_FILE_INFORMATION fi2;
+    GetFileInformationByHandle(h1, &fi1);
+    GetFileInformationByHandle(h2, &fi2);
+    result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
+              fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
+              fi1.nFileIndexLow == fi2.nFileIndexLow);
+  }
+  CloseHandle(h1);
+  CloseHandle(h2);
+  return result;
+#else
+  struct stat fs1, fs2;
+  return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 &&
+          memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 &&
+          memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 &&
+          fs2.st_size == fs1.st_size);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to report a system error message.  */
+static void kwsys_shared_forward_strerror(char* message)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  /* Implementation for Windows.  */
+  DWORD original = GetLastError();
+  DWORD length =
+    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                   0, original, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                   message, KWSYS_SHARED_FORWARD_MAXPATH, 0);
+  if (length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) {
+    /* FormatMessage failed.  Use a default message.  */
+    _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH,
+              "Error 0x%X (FormatMessage failed with error 0x%X)", original,
+              GetLastError());
+  }
+#else
+  /* Implementation for UNIX.  */
+  strcpy(message, strerror(errno));
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* Functions to execute a child process.  */
+static void kwsys_shared_forward_execvp(const char* cmd,
+                                        char const* const* argv)
+{
+#ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV
+  /* Count the number of arguments.  */
+  int argc = 0;
+  {
+    char const* const* argvc;
+    for (argvc = argv; *argvc; ++argvc, ++argc) {
+    }
+  }
+
+  /* Create the escaped arguments.  */
+  {
+    char** nargv = (char**)malloc((argc + 1) * sizeof(char*));
+    int i;
+    for (i = 0; i < argc; ++i) {
+      kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]);
+      nargv[i] = (char*)malloc(info.size);
+      kwsys_sf_get_arg(info, nargv[i]);
+    }
+    nargv[argc] = 0;
+
+    /* Replace the command line to be used.  */
+    argv = (char const* const*)nargv;
+  }
+#endif
+
+/* Invoke the child process.  */
+#if defined(_MSC_VER)
+  _execvp(cmd, argv);
+#elif defined(__MINGW32__) && !defined(__MINGW64__)
+  execvp(cmd, argv);
+#else
+  execvp(cmd, (char* const*)argv);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to get the directory containing the given file or directory.  */
+static void kwsys_shared_forward_dirname(const char* begin, char* result)
+{
+  /* Find the location of the last slash.  */
+  int last_slash_index = -1;
+  const char* end = begin + strlen(begin);
+  for (; begin <= end && last_slash_index < 0; --end) {
+    if (*end == '/' || *end == '\\') {
+      last_slash_index = (int)(end - begin);
+    }
+  }
+
+  /* Handle each case of the index of the last slash.  */
+  if (last_slash_index < 0) {
+    /* No slashes.  */
+    strcpy(result, ".");
+  } else if (last_slash_index == 0) {
+    /* Only one leading slash.  */
+    strcpy(result, kwsys_shared_forward_path_slash);
+  }
+#if defined(_WIN32)
+  else if (last_slash_index == 2 && begin[1] == ':') {
+    /* Only one leading drive letter and slash.  */
+    strncpy(result, begin, (size_t)last_slash_index);
+    result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH;
+    result[last_slash_index + 1] = 0;
+  }
+#endif
+  else {
+    /* A non-leading slash.  */
+    strncpy(result, begin, (size_t)last_slash_index);
+    result[last_slash_index] = 0;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to check if a file exists and is executable.  */
+static int kwsys_shared_forward_is_executable(const char* f)
+{
+#if defined(_MSC_VER)
+#define KWSYS_SHARED_FORWARD_ACCESS _access
+#else
+#define KWSYS_SHARED_FORWARD_ACCESS access
+#endif
+#if defined(X_OK)
+#define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK
+#else
+#define KWSYS_SHARED_FORWARD_ACCESS_OK 04
+#endif
+  if (KWSYS_SHARED_FORWARD_ACCESS(f, KWSYS_SHARED_FORWARD_ACCESS_OK) == 0) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to locate the executable currently running.  */
+static int kwsys_shared_forward_self_path(const char* argv0, char* result)
+{
+  /* Check whether argv0 has a slash.  */
+  int has_slash = 0;
+  const char* p = argv0;
+  for (; *p && !has_slash; ++p) {
+    if (*p == '/' || *p == '\\') {
+      has_slash = 1;
+    }
+  }
+
+  if (has_slash) {
+    /* There is a slash.  Use the dirname of the given location.  */
+    kwsys_shared_forward_dirname(argv0, result);
+    return 1;
+  } else {
+    /* There is no slash.  Search the PATH for the executable.  */
+    const char* path = getenv("PATH");
+    const char* begin = path;
+    const char* end = begin + (begin ? strlen(begin) : 0);
+    const char* first = begin;
+    while (first != end) {
+      /* Store the end of this path entry.  */
+      const char* last;
+
+      /* Skip all path separators.  */
+      for (; *first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first)
+        ;
+
+      /* Find the next separator.  */
+      for (last = first; *last && *last != KWSYS_SHARED_FORWARD_PATH_SEP;
+           ++last)
+        ;
+
+      /* If we got a non-empty directory, look for the executable there.  */
+      if (first < last) {
+        /* Determine the length without trailing slash.  */
+        size_t length = (size_t)(last - first);
+        if (*(last - 1) == '/' || *(last - 1) == '\\') {
+          --length;
+        }
+
+        /* Construct the name of the executable in this location.  */
+        strncpy(result, first, length);
+        result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH;
+        strcpy(result + (length) + 1, argv0);
+
+        /* Check if it exists and is executable.  */
+        if (kwsys_shared_forward_is_executable(result)) {
+          /* Found it.  */
+          result[length] = 0;
+          return 1;
+        }
+      }
+
+      /* Move to the next directory in the path.  */
+      first = last;
+    }
+  }
+
+  /* We could not find the executable.  */
+  return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to convert a specified path to a full path.  If it is not
+   already full, it is taken relative to the self path.  */
+static int kwsys_shared_forward_fullpath(const char* self_path,
+                                         const char* in_path, char* result,
+                                         const char* desc)
+{
+  /* Check the specified path type.  */
+  if (in_path[0] == '/') {
+    /* Already a full path.  */
+    strcpy(result, in_path);
+  }
+#if defined(_WIN32)
+  else if (in_path[0] && in_path[1] == ':') {
+    /* Already a full path.  */
+    strcpy(result, in_path);
+  }
+#endif
+  else {
+    /* Relative to self path.  */
+    char temp_path[KWSYS_SHARED_FORWARD_MAXPATH];
+    strcpy(temp_path, self_path);
+    strcat(temp_path, kwsys_shared_forward_path_slash);
+    strcat(temp_path, in_path);
+    if (!kwsys_shared_forward_realpath(temp_path, result)) {
+      if (desc) {
+        char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH];
+        kwsys_shared_forward_strerror(msgbuf);
+        fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", desc,
+                temp_path, msgbuf);
+      }
+      return 0;
+    }
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to compute the library search path and executable name
+   based on the self path.  */
+static int kwsys_shared_forward_get_settings(const char* self_path,
+                                             char* ldpath, char* exe)
+{
+  /* Possible search paths.  */
+  static const char* search_path_build[] = { KWSYS_SHARED_FORWARD_PATH_BUILD,
+                                             0 };
+  static const char* search_path_install[] = {
+    KWSYS_SHARED_FORWARD_PATH_INSTALL, 0
+  };
+
+  /* Chosen paths.  */
+  const char** search_path;
+  const char* exe_path;
+
+/* Get the real name of the build and self paths.  */
+#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
+  char build_path[] =
+    KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME;
+  char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH];
+#else
+  char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD;
+  const char* self_path_logical = self_path;
+#endif
+  char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH];
+  char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH];
+  if (!kwsys_shared_forward_realpath(self_path, self_path_real)) {
+    char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH];
+    kwsys_shared_forward_strerror(msgbuf);
+    fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n",
+            self_path, msgbuf);
+    return 0;
+  }
+
+  /* Check whether we are running in the build tree or an install tree.  */
+  if (kwsys_shared_forward_realpath(build_path, build_path_real) &&
+      kwsys_shared_forward_samepath(self_path_real, build_path_real)) {
+    /* Running in build tree.  Use the build path and exe.  */
+    search_path = search_path_build;
+#if defined(_WIN32)
+    exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe";
+#else
+    exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD;
+#endif
+
+#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
+    /* Remove the configuration directory from self_path.  */
+    kwsys_shared_forward_dirname(self_path, self_path_logical);
+#endif
+  } else {
+    /* Running in install tree.  Use the install path and exe.  */
+    search_path = search_path_install;
+#if defined(_WIN32)
+    exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe";
+#else
+    exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL;
+#endif
+
+#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
+    /* Use the original self path directory.  */
+    strcpy(self_path_logical, self_path);
+#endif
+  }
+
+  /* Construct the runtime search path.  */
+  {
+    const char** dir;
+    for (dir = search_path; *dir; ++dir) {
+      /* Add separator between path components.  */
+      if (dir != search_path) {
+        strcat(ldpath, kwsys_shared_forward_path_sep);
+      }
+
+      /* Add this path component.  */
+      if (!kwsys_shared_forward_fullpath(self_path_logical, *dir,
+                                         ldpath + strlen(ldpath),
+                                         "runtime path entry")) {
+        return 0;
+      }
+    }
+  }
+
+  /* Construct the executable location.  */
+  if (!kwsys_shared_forward_fullpath(self_path_logical, exe_path, exe,
+                                     "executable file")) {
+    return 0;
+  }
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Function to print why execution of a command line failed.  */
+static void kwsys_shared_forward_print_failure(char const* const* argv)
+{
+  char msg[KWSYS_SHARED_FORWARD_MAXPATH];
+  char const* const* arg = argv;
+  kwsys_shared_forward_strerror(msg);
+  fprintf(stderr, "Error running");
+  for (; *arg; ++arg) {
+    fprintf(stderr, " \"%s\"", *arg);
+  }
+  fprintf(stderr, ": %s\n", msg);
+}
+
+/* Static storage space to store the updated environment variable.  */
+static char kwsys_shared_forward_ldpath[65535] =
+  KWSYS_SHARED_FORWARD_LDPATH "=";
+
+/*--------------------------------------------------------------------------*/
+/* Main driver function to be called from main.  */
+static int @KWSYS_NAMESPACE@_shared_forward_to_real(int argc, char** argv_in)
+{
+  char const** argv = (char const**)argv_in;
+  /* Get the directory containing this executable.  */
+  char self_path[KWSYS_SHARED_FORWARD_MAXPATH];
+  if (kwsys_shared_forward_self_path(argv[0], self_path)) {
+    /* Found this executable.  Use it to get the library directory.  */
+    char exe[KWSYS_SHARED_FORWARD_MAXPATH];
+    if (kwsys_shared_forward_get_settings(self_path,
+                                          kwsys_shared_forward_ldpath, exe)) {
+      /* Append the old runtime search path.  */
+      const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH);
+      if (old_ldpath) {
+        strcat(kwsys_shared_forward_ldpath, kwsys_shared_forward_path_sep);
+        strcat(kwsys_shared_forward_ldpath, old_ldpath);
+      }
+
+      /* Store the environment variable.  */
+      putenv(kwsys_shared_forward_ldpath);
+
+#if defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND)
+      /* Look for the command line replacement option.  */
+      if (argc > 1 &&
+          strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0) {
+        if (argc > 2) {
+          /* Use the command line given.  */
+          strcpy(exe, argv[2]);
+          argv += 2;
+          argc -= 2;
+        } else {
+          /* The option was not given an executable.  */
+          fprintf(stderr, "Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND
+                          " must be followed by a command line.\n");
+          return 1;
+        }
+      }
+#endif
+
+#if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT)
+      /* Look for the print command line option.  */
+      if (argc > 1 &&
+          strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0) {
+        fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath);
+        fprintf(stdout, "%s\n", exe);
+        return 0;
+      }
+#endif
+
+#if defined(KWSYS_SHARED_FORWARD_OPTION_LDD)
+      /* Look for the ldd command line option.  */
+      if (argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0) {
+#if defined(KWSYS_SHARED_FORWARD_LDD)
+        /* Use the named ldd-like executable and arguments.  */
+        char const* ldd_argv[] = { KWSYS_SHARED_FORWARD_LDD, 0, 0 };
+        ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe;
+        kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv);
+
+        /* Report why execution failed.  */
+        kwsys_shared_forward_print_failure(ldd_argv);
+        return 1;
+#else
+        /* We have no ldd-like executable available on this platform.  */
+        fprintf(stderr, "No ldd-like tool is known to this executable.\n");
+        return 1;
+#endif
+      }
+#endif
+
+      /* Replace this process with the real executable.  */
+      argv[0] = exe;
+      kwsys_shared_forward_execvp(argv[0], argv);
+
+      /* Report why execution failed.  */
+      kwsys_shared_forward_print_failure(argv);
+    } else {
+      /* Could not convert self path to the library directory.  */
+    }
+  } else {
+    /* Could not find this executable.  */
+    fprintf(stderr, "Error locating executable \"%s\".\n", argv[0]);
+  }
+
+  /* Avoid unused argument warning.  */
+  (void)argc;
+
+  /* Exit with failure.  */
+  return 1;
+}
+
+/* Restore warning stack.  */
+#if defined(__clang__) && defined(__has_warning)
+#if __has_warning("-Wcast-qual")
+#pragma clang diagnostic pop
+#endif
+#endif
+
+#else
+#error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once."
+#endif
diff --git a/thirdparty/KWSys/adios2sys/String.c b/thirdparty/KWSys/adios2sys/String.c
new file mode 100644
index 0000000000000000000000000000000000000000..048222968c6a1e47f2a1a3396191c2a4b4723bcf
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/String.c
@@ -0,0 +1,100 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifdef KWSYS_STRING_C
+/*
+All code in this source file is conditionally compiled to work-around
+template definition auto-search on VMS.  Other source files in this
+directory that use the stl string cause the compiler to load this
+source to try to get the definition of the string template.  This
+condition blocks the compiler from seeing the symbols defined here.
+*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(String.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "String.h.in"
+#endif
+
+/* Select an implementation for strcasecmp.  */
+#if defined(_MSC_VER)
+#define KWSYS_STRING_USE_STRICMP
+#include <string.h>
+#elif defined(__GNUC__)
+#define KWSYS_STRING_USE_STRCASECMP
+#include <strings.h>
+#else
+/* Table to convert upper case letters to lower case and leave all
+   other characters alone.  */
+static char kwsysString_strcasecmp_tolower[] = {
+  '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010',
+  '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021',
+  '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032',
+  '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043',
+  '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054',
+  '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065',
+  '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076',
+  '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+  '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160',
+  '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171',
+  '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142',
+  '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153',
+  '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164',
+  '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175',
+  '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206',
+  '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+  '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230',
+  '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241',
+  '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252',
+  '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263',
+  '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274',
+  '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305',
+  '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316',
+  '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+  '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340',
+  '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351',
+  '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362',
+  '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373',
+  '\374', '\375', '\376', '\377'
+};
+#endif
+
+/*--------------------------------------------------------------------------*/
+int kwsysString_strcasecmp(const char* lhs, const char* rhs)
+{
+#if defined(KWSYS_STRING_USE_STRICMP)
+  return _stricmp(lhs, rhs);
+#elif defined(KWSYS_STRING_USE_STRCASECMP)
+  return strcasecmp(lhs, rhs);
+#else
+  const char* const lower = kwsysString_strcasecmp_tolower;
+  unsigned char const* us1 = (unsigned char const*)lhs;
+  unsigned char const* us2 = (unsigned char const*)rhs;
+  int result;
+  while ((result = lower[*us1] - lower[*us2++], result == 0) && *us1++) {
+  }
+  return result;
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysString_strncasecmp(const char* lhs, const char* rhs, size_t n)
+{
+#if defined(KWSYS_STRING_USE_STRICMP)
+  return _strnicmp(lhs, rhs, n);
+#elif defined(KWSYS_STRING_USE_STRCASECMP)
+  return strncasecmp(lhs, rhs, n);
+#else
+  const char* const lower = kwsysString_strcasecmp_tolower;
+  unsigned char const* us1 = (unsigned char const*)lhs;
+  unsigned char const* us2 = (unsigned char const*)rhs;
+  int result = 0;
+  while (n && (result = lower[*us1] - lower[*us2++], result == 0) && *us1++) {
+    --n;
+  }
+  return result;
+#endif
+}
+
+#endif /* KWSYS_STRING_C */
diff --git a/thirdparty/KWSys/adios2sys/String.h.in b/thirdparty/KWSys/adios2sys/String.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..3c1d571c0016a08c061267bd3baf65efdc0a0aed
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/String.h.in
@@ -0,0 +1,57 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_String_h
+#define @KWSYS_NAMESPACE@_String_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+#include <stddef.h> /* size_t */
+
+/* Redefine all public interface symbol names to be in the proper
+   namespace.  These macros are used internally to kwsys only, and are
+   not visible to user code.  Use kwsysHeaderDump.pl to reproduce
+   these macros after making changes to the interface.  */
+#if !defined(KWSYS_NAMESPACE)
+#define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsysString_strcasecmp kwsys_ns(String_strcasecmp)
+#define kwsysString_strncasecmp kwsys_ns(String_strncasecmp)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Compare two strings ignoring the case of the characters.  The
+ * integer returned is negative, zero, or positive if the first string
+ * is found to be less than, equal to, or greater than the second
+ * string, respectively.
+ */
+kwsysEXPORT int kwsysString_strcasecmp(const char* lhs, const char* rhs);
+
+/**
+ * Identical to String_strcasecmp except that only the first n
+ * characters are considered.
+ */
+kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs,
+                                        size_t n);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+   Otherwise, undefine them to keep the namespace clean.  */
+#if !defined(KWSYS_NAMESPACE)
+#undef kwsys_ns
+#undef kwsysEXPORT
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#undef kwsysString_strcasecmp
+#undef kwsysString_strncasecmp
+#endif
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/String.hxx.in b/thirdparty/KWSys/adios2sys/String.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..db1cf22a93af80fc70e51c204f0cf6d75cfaf6b8
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/String.hxx.in
@@ -0,0 +1,65 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_String_hxx
+#define @KWSYS_NAMESPACE@_String_hxx
+
+#include <string>
+
+namespace @KWSYS_NAMESPACE@ {
+
+/** \class String
+ * \brief Short-name version of the STL basic_string class template.
+ *
+ * The standard library "string" type is actually a typedef for
+ * "basic_string<..long argument list..>".  This string class is
+ * simply a subclass of this type with the same interface so that the
+ * name is shorter in debugging symbols and error messages.
+ */
+class String : public std::string
+{
+  /** The original string type.  */
+  typedef std::string stl_string;
+
+public:
+  /** String member types.  */
+  typedef stl_string::value_type value_type;
+  typedef stl_string::pointer pointer;
+  typedef stl_string::reference reference;
+  typedef stl_string::const_reference const_reference;
+  typedef stl_string::size_type size_type;
+  typedef stl_string::difference_type difference_type;
+  typedef stl_string::iterator iterator;
+  typedef stl_string::const_iterator const_iterator;
+  typedef stl_string::reverse_iterator reverse_iterator;
+  typedef stl_string::const_reverse_iterator const_reverse_iterator;
+
+  /** String constructors.  */
+  String()
+    : stl_string()
+  {
+  }
+  String(const value_type* s)
+    : stl_string(s)
+  {
+  }
+  String(const value_type* s, size_type n)
+    : stl_string(s, n)
+  {
+  }
+  String(const stl_string& s, size_type pos = 0, size_type n = npos)
+    : stl_string(s, pos, n)
+  {
+  }
+}; // End Class: String
+
+#if defined(__WATCOMC__)
+inline bool operator<(String const& l, String const& r)
+{
+  return (static_cast<std::string const&>(l) <
+          static_cast<std::string const&>(r));
+}
+#endif
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/System.c b/thirdparty/KWSys/adios2sys/System.c
new file mode 100644
index 0000000000000000000000000000000000000000..43c60c5722c7882f60994dcb4e9ba0f5a5adea6b
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/System.c
@@ -0,0 +1,240 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(System.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "System.h.in"
+#endif
+
+#include <ctype.h>  /* isspace */
+#include <stddef.h> /* ptrdiff_t */
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memcpy */
+
+#include <stdio.h>
+
+#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T
+typedef ptrdiff_t kwsysSystem_ptrdiff_t;
+#else
+typedef int kwsysSystem_ptrdiff_t;
+#endif
+
+/*--------------------------------------------------------------------------*/
+static int kwsysSystem__AppendByte(char* local, char** begin, char** end,
+                                   int* size, char c)
+{
+  /* Allocate space for the character.  */
+  if ((*end - *begin) >= *size) {
+    kwsysSystem_ptrdiff_t length = *end - *begin;
+    char* newBuffer = (char*)malloc((size_t)(*size * 2));
+    if (!newBuffer) {
+      return 0;
+    }
+    memcpy(newBuffer, *begin, (size_t)(length) * sizeof(char));
+    if (*begin != local) {
+      free(*begin);
+    }
+    *begin = newBuffer;
+    *end = *begin + length;
+    *size *= 2;
+  }
+
+  /* Store the character.  */
+  *(*end)++ = c;
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysSystem__AppendArgument(char** local, char*** begin,
+                                       char*** end, int* size, char* arg_local,
+                                       char** arg_begin, char** arg_end,
+                                       int* arg_size)
+{
+  /* Append a null-terminator to the argument string.  */
+  if (!kwsysSystem__AppendByte(arg_local, arg_begin, arg_end, arg_size,
+                               '\0')) {
+    return 0;
+  }
+
+  /* Allocate space for the argument pointer.  */
+  if ((*end - *begin) >= *size) {
+    kwsysSystem_ptrdiff_t length = *end - *begin;
+    char** newPointers = (char**)malloc((size_t)(*size) * 2 * sizeof(char*));
+    if (!newPointers) {
+      return 0;
+    }
+    memcpy(newPointers, *begin, (size_t)(length) * sizeof(char*));
+    if (*begin != local) {
+      free(*begin);
+    }
+    *begin = newPointers;
+    *end = *begin + length;
+    *size *= 2;
+  }
+
+  /* Allocate space for the argument string.  */
+  **end = (char*)malloc((size_t)(*arg_end - *arg_begin));
+  if (!**end) {
+    return 0;
+  }
+
+  /* Store the argument in the command array.  */
+  memcpy(**end, *arg_begin, (size_t)(*arg_end - *arg_begin));
+  ++(*end);
+
+  /* Reset the argument to be empty.  */
+  *arg_end = *arg_begin;
+
+  return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+#define KWSYSPE_LOCAL_BYTE_COUNT 1024
+#define KWSYSPE_LOCAL_ARGS_COUNT 32
+static char** kwsysSystem__ParseUnixCommand(const char* command, int flags)
+{
+  /* Create a buffer for argument pointers during parsing.  */
+  char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT];
+  int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT;
+  char** pointer_begin = local_pointers;
+  char** pointer_end = pointer_begin;
+
+  /* Create a buffer for argument strings during parsing.  */
+  char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT];
+  int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT;
+  char* buffer_begin = local_buffer;
+  char* buffer_end = buffer_begin;
+
+  /* Parse the command string.  Try to behave like a UNIX shell.  */
+  char** newCommand = 0;
+  const char* c = command;
+  int in_argument = 0;
+  int in_escape = 0;
+  int in_single = 0;
+  int in_double = 0;
+  int failed = 0;
+  for (; *c; ++c) {
+    if (in_escape) {
+      /* This character is escaped so do no special handling.  */
+      if (!in_argument) {
+        in_argument = 1;
+      }
+      if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end,
+                                   &buffer_size, *c)) {
+        failed = 1;
+        break;
+      }
+      in_escape = 0;
+    } else if (*c == '\\') {
+      /* The next character should be escaped.  */
+      in_escape = 1;
+    } else if (*c == '\'' && !in_double) {
+      /* Enter or exit single-quote state.  */
+      if (in_single) {
+        in_single = 0;
+      } else {
+        in_single = 1;
+        if (!in_argument) {
+          in_argument = 1;
+        }
+      }
+    } else if (*c == '"' && !in_single) {
+      /* Enter or exit double-quote state.  */
+      if (in_double) {
+        in_double = 0;
+      } else {
+        in_double = 1;
+        if (!in_argument) {
+          in_argument = 1;
+        }
+      }
+    } else if (isspace((unsigned char)*c)) {
+      if (in_argument) {
+        if (in_single || in_double) {
+          /* This space belongs to a quoted argument.  */
+          if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin,
+                                       &buffer_end, &buffer_size, *c)) {
+            failed = 1;
+            break;
+          }
+        } else {
+          /* This argument has been terminated by whitespace.  */
+          if (!kwsysSystem__AppendArgument(
+                local_pointers, &pointer_begin, &pointer_end, &pointers_size,
+                local_buffer, &buffer_begin, &buffer_end, &buffer_size)) {
+            failed = 1;
+            break;
+          }
+          in_argument = 0;
+        }
+      }
+    } else {
+      /* This character belong to an argument.  */
+      if (!in_argument) {
+        in_argument = 1;
+      }
+      if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end,
+                                   &buffer_size, *c)) {
+        failed = 1;
+        break;
+      }
+    }
+  }
+
+  /* Finish the last argument.  */
+  if (in_argument) {
+    if (!kwsysSystem__AppendArgument(
+          local_pointers, &pointer_begin, &pointer_end, &pointers_size,
+          local_buffer, &buffer_begin, &buffer_end, &buffer_size)) {
+      failed = 1;
+    }
+  }
+
+  /* If we still have memory allocate space for the new command
+     buffer.  */
+  if (!failed) {
+    kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin;
+    newCommand = (char**)malloc((size_t)(n + 1) * sizeof(char*));
+  }
+
+  if (newCommand) {
+    /* Copy the arguments into the new command buffer.  */
+    kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin;
+    memcpy(newCommand, pointer_begin, sizeof(char*) * (size_t)(n));
+    newCommand[n] = 0;
+  } else {
+    /* Free arguments already allocated.  */
+    while (pointer_end != pointer_begin) {
+      free(*(--pointer_end));
+    }
+  }
+
+  /* Free temporary buffers.  */
+  if (pointer_begin != local_pointers) {
+    free(pointer_begin);
+  }
+  if (buffer_begin != local_buffer) {
+    free(buffer_begin);
+  }
+
+  /* The flags argument is currently unused.  */
+  (void)flags;
+
+  /* Return the final command buffer.  */
+  return newCommand;
+}
+
+/*--------------------------------------------------------------------------*/
+char** kwsysSystem_Parse_CommandForUnix(const char* command, int flags)
+{
+  /* Validate the flags.  */
+  if (flags != 0) {
+    return 0;
+  }
+
+  /* Forward to our internal implementation.  */
+  return kwsysSystem__ParseUnixCommand(command, flags);
+}
diff --git a/thirdparty/KWSys/adios2sys/System.h.in b/thirdparty/KWSys/adios2sys/System.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..102974db7a8621269a2646085fad342088c066a9
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/System.h.in
@@ -0,0 +1,59 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_System_h
+#define @KWSYS_NAMESPACE@_System_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+/* Redefine all public interface symbol names to be in the proper
+   namespace.  These macros are used internally to kwsys only, and are
+   not visible to user code.  Use kwsysHeaderDump.pl to reproduce
+   these macros after making changes to the interface.  */
+#if !defined(KWSYS_NAMESPACE)
+#define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsysSystem_Parse_CommandForUnix kwsys_ns(System_Parse_CommandForUnix)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Parse a unix-style command line string into separate arguments.
+ *
+ * On success, returns a pointer to an array of pointers to individual
+ * argument strings.  Each string is null-terminated and the last
+ * entry in the array is a NULL pointer (just like argv).  It is the
+ * caller's responsibility to free() the strings and the array of
+ * pointers to them.
+ *
+ * On failure, returns NULL.  Failure occurs only on invalid flags or
+ * when memory cannot be allocated; never due to content of the input
+ * string.  Missing close-quotes are treated as if the necessary
+ * closing quote appears.
+ *
+ * By default single- and double-quoted arguments are supported, and
+ * any character may be escaped by a backslash.  The flags argument is
+ * reserved for future use, and must be zero (or the call will fail).
+ */
+kwsysEXPORT char** kwsysSystem_Parse_CommandForUnix(const char* command,
+                                                    int flags);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+   Otherwise, undefine them to keep the namespace clean.  */
+#if !defined(KWSYS_NAMESPACE)
+#undef kwsys_ns
+#undef kwsysEXPORT
+#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#undef kwsysSystem_Parse_CommandForUnix
+#endif
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/SystemInformation.cxx b/thirdparty/KWSys/adios2sys/SystemInformation.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..70f1a434ed914f0008ffe1abec8fd69c00ec072a
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/SystemInformation.cxx
@@ -0,0 +1,5427 @@
+/* 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 // use our min,max
+#if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
+#define _WIN32_WINNT 0x0501
+#endif
+#include <winsock.h> // WSADATA, include before sys/types.h
+#endif
+
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+
+// TODO:
+// We need an alternative implementation for many functions in this file
+// when USE_ASM_INSTRUCTIONS gets defined as 0.
+//
+// Consider using these on Win32/Win64 for some of them:
+//
+// IsProcessorFeaturePresent
+// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx
+//
+// GetProcessMemoryInfo
+// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx
+
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(SystemInformation.hxx)
+#include KWSYS_HEADER(Process.h)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Process.h.in"
+#include "SystemInformation.hxx.in"
+#endif
+
+#include <algorithm>
+#include <bitset>
+#include <cassert>
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#if defined(_WIN32)
+#include <windows.h>
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#endif
+#include <errno.h>
+#if defined(KWSYS_SYS_HAS_PSAPI)
+#include <psapi.h>
+#endif
+#if !defined(siginfo_t)
+typedef int siginfo_t;
+#endif
+#else
+#include <sys/types.h>
+
+#include <errno.h> // extern int errno;
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/resource.h> // getrlimit
+#include <sys/time.h>
+#include <sys/utsname.h> // int uname(struct utsname *buf);
+#include <unistd.h>
+#endif
+
+#if defined(__CYGWIN__) && !defined(_WIN32)
+#include <windows.h>
+#undef _WIN32
+#endif
+
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
+  defined(__DragonFly__)
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#if defined(KWSYS_SYS_HAS_IFADDRS_H)
+#include <ifaddrs.h>
+#include <net/if.h>
+#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+#endif
+#endif
+
+#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
+#include <machine/cpu.h>
+#endif
+
+#ifdef __APPLE__
+#include <fenv.h>
+#include <mach/host_info.h>
+#include <mach/mach.h>
+#include <mach/mach_types.h>
+#include <mach/vm_statistics.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#if defined(KWSYS_SYS_HAS_IFADDRS_H)
+#include <ifaddrs.h>
+#include <net/if.h>
+#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+#endif
+#if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050)
+#undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
+#endif
+#endif
+
+#if defined(__linux) || defined(__sun) || defined(_SCO_DS)
+#include <fenv.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#if defined(KWSYS_SYS_HAS_IFADDRS_H)
+#include <ifaddrs.h>
+#include <net/if.h>
+#if !defined(__LSB_VERSION__) /* LSB has no getifaddrs */
+#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+#endif
+#endif
+#if defined(KWSYS_CXX_HAS_RLIMIT64)
+typedef struct rlimit64 ResourceLimitType;
+#define GetResourceLimit getrlimit64
+#else
+typedef struct rlimit ResourceLimitType;
+#define GetResourceLimit getrlimit
+#endif
+#elif defined(__hpux)
+#include <sys/param.h>
+#include <sys/pstat.h>
+#if defined(KWSYS_SYS_HAS_MPCTL_H)
+#include <sys/mpctl.h>
+#endif
+#endif
+
+#ifdef __HAIKU__
+#include <OS.h>
+#endif
+
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+#include <execinfo.h>
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
+#include <cxxabi.h>
+#endif
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+#include <dlfcn.h>
+#endif
+#else
+#undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE
+#undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
+#endif
+
+#include <ctype.h> // int isdigit(int c);
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(KWSYS_USE_LONG_LONG)
+#if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
+#define iostreamLongLong(x) (x)
+#else
+#define iostreamLongLong(x) ((long)(x))
+#endif
+#elif defined(KWSYS_USE___INT64)
+#if defined(KWSYS_IOS_HAS_OSTREAM___INT64)
+#define iostreamLongLong(x) (x)
+#else
+#define iostreamLongLong(x) ((long)(x))
+#endif
+#else
+#error "No Long Long"
+#endif
+
+#if defined(KWSYS_CXX_HAS_ATOLL)
+#define atoLongLong atoll
+#else
+#if defined(KWSYS_CXX_HAS__ATOI64)
+#define atoLongLong _atoi64
+#elif defined(KWSYS_CXX_HAS_ATOL)
+#define atoLongLong atol
+#else
+#define atoLongLong atoi
+#endif
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) &&            \
+  !defined(__clang__)
+#define USE_ASM_INSTRUCTIONS 1
+#else
+#define USE_ASM_INSTRUCTIONS 0
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__)
+#include <intrin.h>
+#define USE_CPUID_INTRINSICS 1
+#else
+#define USE_CPUID_INTRINSICS 0
+#endif
+
+#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS ||                           \
+  defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
+#define USE_CPUID 1
+#else
+#define USE_CPUID 0
+#endif
+
+#if USE_CPUID
+
+#define CPUID_AWARE_COMPILER
+
+/**
+ * call CPUID instruction
+ *
+ * Will return false if the instruction failed.
+ */
+static bool call_cpuid(int select, int result[4])
+{
+#if USE_CPUID_INTRINSICS
+  __cpuid(result, select);
+  return true;
+#else
+  int tmp[4];
+#if defined(_MSC_VER)
+  // Use SEH to determine CPUID presence
+  __try {
+    _asm {
+#ifdef CPUID_AWARE_COMPILER
+      ; we must push/pop the registers <<CPUID>> writes to, as the
+      ; optimiser does not know about <<CPUID>>, and so does not expect
+      ; these registers to change.
+      push eax
+      push ebx
+      push ecx
+      push edx
+#endif
+      ; <<CPUID>>
+      mov eax, select
+#ifdef CPUID_AWARE_COMPILER
+      cpuid
+#else
+      _asm _emit 0x0f
+      _asm _emit 0xa2
+#endif
+      mov tmp[0 * TYPE int], eax
+      mov tmp[1 * TYPE int], ebx
+      mov tmp[2 * TYPE int], ecx
+      mov tmp[3 * TYPE int], edx
+
+#ifdef CPUID_AWARE_COMPILER
+      pop edx
+      pop ecx
+      pop ebx
+      pop eax
+#endif
+    }
+  } __except (1) {
+    return false;
+  }
+
+  memcpy(result, tmp, sizeof(tmp));
+#elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
+  unsigned int a, b, c, d;
+  __asm {
+    mov EAX, select;
+    cpuid
+    mov a, EAX;
+    mov b, EBX;
+    mov c, ECX;
+    mov d, EDX;
+  }
+
+  result[0] = a;
+  result[1] = b;
+  result[2] = c;
+  result[3] = d;
+#endif
+
+  // The cpuid instruction succeeded.
+  return true;
+#endif
+}
+#endif
+
+namespace KWSYS_NAMESPACE {
+template <typename T>
+T min(T a, T b)
+{
+  return a < b ? a : b;
+}
+
+extern "C" {
+typedef void (*SigAction)(int, siginfo_t*, void*);
+}
+
+//  Define SystemInformationImplementation class
+typedef void (*DELAY_FUNC)(unsigned int uiMS);
+
+class SystemInformationImplementation
+{
+public:
+  typedef SystemInformation::LongLong LongLong;
+  SystemInformationImplementation();
+  ~SystemInformationImplementation();
+
+  const char* GetVendorString();
+  const char* GetVendorID();
+  std::string GetTypeID();
+  std::string GetFamilyID();
+  std::string GetModelID();
+  std::string GetModelName();
+  std::string GetSteppingCode();
+  const char* GetExtendedProcessorName();
+  const char* GetProcessorSerialNumber();
+  int GetProcessorCacheSize();
+  unsigned int GetLogicalProcessorsPerPhysical();
+  float GetProcessorClockFrequency();
+  int GetProcessorAPICID();
+  int GetProcessorCacheXSize(long int);
+  bool DoesCPUSupportFeature(long int);
+
+  const char* GetOSName();
+  const char* GetHostname();
+  int GetFullyQualifiedDomainName(std::string& fqdn);
+  const char* GetOSRelease();
+  const char* GetOSVersion();
+  const char* GetOSPlatform();
+
+  bool Is64Bits();
+
+  unsigned int GetNumberOfLogicalCPU(); // per physical cpu
+  unsigned int GetNumberOfPhysicalCPU();
+
+  bool DoesCPUSupportCPUID();
+
+  // Retrieve memory information in megabyte.
+  size_t GetTotalVirtualMemory();
+  size_t GetAvailableVirtualMemory();
+  size_t GetTotalPhysicalMemory();
+  size_t GetAvailablePhysicalMemory();
+
+  LongLong GetProcessId();
+
+  // Retrieve memory information in kib
+  LongLong GetHostMemoryTotal();
+  LongLong GetHostMemoryAvailable(const char* envVarName);
+  LongLong GetHostMemoryUsed();
+
+  LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName,
+                                  const char* procLimitEnvVarName);
+  LongLong GetProcMemoryUsed();
+
+  double GetLoadAverage();
+
+  // enable/disable stack trace signal handler.
+  static void SetStackTraceOnError(int enable);
+
+  // get current stack
+  static std::string GetProgramStack(int firstFrame, int wholePath);
+
+  /** Run the different checks */
+  void RunCPUCheck();
+  void RunOSCheck();
+  void RunMemoryCheck();
+
+public:
+  typedef struct tagID
+  {
+    int Type;
+    int Family;
+    int Model;
+    int Revision;
+    int ExtendedFamily;
+    int ExtendedModel;
+    std::string ProcessorName;
+    std::string Vendor;
+    std::string SerialNumber;
+    std::string ModelName;
+  } ID;
+
+  typedef struct tagCPUPowerManagement
+  {
+    bool HasVoltageID;
+    bool HasFrequencyID;
+    bool HasTempSenseDiode;
+  } CPUPowerManagement;
+
+  typedef struct tagCPUExtendedFeatures
+  {
+    bool Has3DNow;
+    bool Has3DNowPlus;
+    bool SupportsMP;
+    bool HasMMXPlus;
+    bool HasSSEMMX;
+    unsigned int LogicalProcessorsPerPhysical;
+    int APIC_ID;
+    CPUPowerManagement PowerManagement;
+  } CPUExtendedFeatures;
+
+  typedef struct CPUtagFeatures
+  {
+    bool HasFPU;
+    bool HasTSC;
+    bool HasMMX;
+    bool HasSSE;
+    bool HasSSEFP;
+    bool HasSSE2;
+    bool HasIA64;
+    bool HasAPIC;
+    bool HasCMOV;
+    bool HasMTRR;
+    bool HasACPI;
+    bool HasSerial;
+    bool HasThermal;
+    int CPUSpeed;
+    int L1CacheSize;
+    int L2CacheSize;
+    int L3CacheSize;
+    CPUExtendedFeatures ExtendedFeatures;
+  } CPUFeatures;
+
+  enum Manufacturer
+  {
+    AMD,
+    Intel,
+    NSC,
+    UMC,
+    Cyrix,
+    NexGen,
+    IDT,
+    Rise,
+    Transmeta,
+    Sun,
+    IBM,
+    Motorola,
+    HP,
+    UnknownManufacturer
+  };
+
+protected:
+  // For windows
+  bool RetrieveCPUFeatures();
+  bool RetrieveCPUIdentity();
+  bool RetrieveCPUCacheDetails();
+  bool RetrieveClassicalCPUCacheDetails();
+  bool RetrieveCPUClockSpeed();
+  bool RetrieveClassicalCPUClockSpeed();
+  bool RetrieveCPUExtendedLevelSupport(int);
+  bool RetrieveExtendedCPUFeatures();
+  bool RetrieveProcessorSerialNumber();
+  bool RetrieveCPUPowerManagement();
+  bool RetrieveClassicalCPUIdentity();
+  bool RetrieveExtendedCPUIdentity();
+
+  // Processor information
+  Manufacturer ChipManufacturer;
+  CPUFeatures Features;
+  ID ChipID;
+  float CPUSpeedInMHz;
+  unsigned int NumberOfLogicalCPU;
+  unsigned int NumberOfPhysicalCPU;
+
+  void CPUCountWindows();    // For windows
+  unsigned char GetAPICId(); // For windows
+  bool IsSMTSupported();
+  static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows
+
+  // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
+  bool RetreiveInformationFromCpuInfoFile();
+  std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word,
+                                          size_t init = 0);
+
+  bool QueryLinuxMemory();
+  bool QueryCygwinMemory();
+
+  static void Delay(unsigned int);
+  static void DelayOverhead(unsigned int);
+
+  void FindManufacturer(const std::string& family = "");
+
+  // For Mac
+  bool ParseSysCtl();
+  int CallSwVers(const char* arg, std::string& ver);
+  void TrimNewline(std::string&);
+  std::string ExtractValueFromSysCtl(const char* word);
+  std::string SysCtlBuffer;
+
+  // For Solaris
+  bool QuerySolarisMemory();
+  bool QuerySolarisProcessor();
+  std::string ParseValueFromKStat(const char* arguments);
+  std::string RunProcess(std::vector<const char*> args);
+
+  // For Haiku OS
+  bool QueryHaikuInfo();
+
+  // For QNX
+  bool QueryQNXMemory();
+  bool QueryQNXProcessor();
+
+  // For OpenBSD, FreeBSD, NetBSD, DragonFly
+  bool QueryBSDMemory();
+  bool QueryBSDProcessor();
+
+  // For HP-UX
+  bool QueryHPUXMemory();
+  bool QueryHPUXProcessor();
+
+  // For Microsoft Windows
+  bool QueryWindowsMemory();
+
+  // For AIX
+  bool QueryAIXMemory();
+
+  bool QueryProcessorBySysconf();
+  bool QueryProcessor();
+
+  // Evaluate the memory information.
+  bool QueryMemoryBySysconf();
+  bool QueryMemory();
+  size_t TotalVirtualMemory;
+  size_t AvailableVirtualMemory;
+  size_t TotalPhysicalMemory;
+  size_t AvailablePhysicalMemory;
+
+  size_t CurrentPositionInFile;
+
+  // Operating System information
+  bool QueryOSInformation();
+  std::string OSName;
+  std::string Hostname;
+  std::string OSRelease;
+  std::string OSVersion;
+  std::string OSPlatform;
+  bool OSIs64Bit;
+};
+
+SystemInformation::SystemInformation()
+{
+  this->Implementation = new SystemInformationImplementation;
+}
+
+SystemInformation::~SystemInformation()
+{
+  delete this->Implementation;
+}
+
+const char* SystemInformation::GetVendorString()
+{
+  return this->Implementation->GetVendorString();
+}
+
+const char* SystemInformation::GetVendorID()
+{
+  return this->Implementation->GetVendorID();
+}
+
+std::string SystemInformation::GetTypeID()
+{
+  return this->Implementation->GetTypeID();
+}
+
+std::string SystemInformation::GetFamilyID()
+{
+  return this->Implementation->GetFamilyID();
+}
+
+std::string SystemInformation::GetModelID()
+{
+  return this->Implementation->GetModelID();
+}
+
+std::string SystemInformation::GetModelName()
+{
+  return this->Implementation->GetModelName();
+}
+
+std::string SystemInformation::GetSteppingCode()
+{
+  return this->Implementation->GetSteppingCode();
+}
+
+const char* SystemInformation::GetExtendedProcessorName()
+{
+  return this->Implementation->GetExtendedProcessorName();
+}
+
+const char* SystemInformation::GetProcessorSerialNumber()
+{
+  return this->Implementation->GetProcessorSerialNumber();
+}
+
+int SystemInformation::GetProcessorCacheSize()
+{
+  return this->Implementation->GetProcessorCacheSize();
+}
+
+unsigned int SystemInformation::GetLogicalProcessorsPerPhysical()
+{
+  return this->Implementation->GetLogicalProcessorsPerPhysical();
+}
+
+float SystemInformation::GetProcessorClockFrequency()
+{
+  return this->Implementation->GetProcessorClockFrequency();
+}
+
+int SystemInformation::GetProcessorAPICID()
+{
+  return this->Implementation->GetProcessorAPICID();
+}
+
+int SystemInformation::GetProcessorCacheXSize(long int l)
+{
+  return this->Implementation->GetProcessorCacheXSize(l);
+}
+
+bool SystemInformation::DoesCPUSupportFeature(long int i)
+{
+  return this->Implementation->DoesCPUSupportFeature(i);
+}
+
+std::string SystemInformation::GetCPUDescription()
+{
+  std::ostringstream oss;
+  oss << this->GetNumberOfPhysicalCPU() << " core ";
+  if (this->GetModelName().empty()) {
+    oss << this->GetProcessorClockFrequency() << " MHz "
+        << this->GetVendorString() << " " << this->GetExtendedProcessorName();
+  } else {
+    oss << this->GetModelName();
+  }
+
+  // remove extra spaces
+  std::string tmp = oss.str();
+  size_t pos;
+  while ((pos = tmp.find("  ")) != std::string::npos) {
+    tmp.replace(pos, 2, " ");
+  }
+
+  return tmp;
+}
+
+const char* SystemInformation::GetOSName()
+{
+  return this->Implementation->GetOSName();
+}
+
+const char* SystemInformation::GetHostname()
+{
+  return this->Implementation->GetHostname();
+}
+
+std::string SystemInformation::GetFullyQualifiedDomainName()
+{
+  std::string fqdn;
+  this->Implementation->GetFullyQualifiedDomainName(fqdn);
+  return fqdn;
+}
+
+const char* SystemInformation::GetOSRelease()
+{
+  return this->Implementation->GetOSRelease();
+}
+
+const char* SystemInformation::GetOSVersion()
+{
+  return this->Implementation->GetOSVersion();
+}
+
+const char* SystemInformation::GetOSPlatform()
+{
+  return this->Implementation->GetOSPlatform();
+}
+
+int SystemInformation::GetOSIsWindows()
+{
+#if defined(_WIN32)
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+int SystemInformation::GetOSIsLinux()
+{
+#if defined(__linux)
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+int SystemInformation::GetOSIsApple()
+{
+#if defined(__APPLE__)
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+std::string SystemInformation::GetOSDescription()
+{
+  std::ostringstream oss;
+  oss << this->GetOSName() << " " << this->GetOSRelease() << " "
+      << this->GetOSVersion();
+
+  return oss.str();
+}
+
+bool SystemInformation::Is64Bits()
+{
+  return this->Implementation->Is64Bits();
+}
+
+unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
+{
+  return this->Implementation->GetNumberOfLogicalCPU();
+}
+
+unsigned int SystemInformation::GetNumberOfPhysicalCPU()
+{
+  return this->Implementation->GetNumberOfPhysicalCPU();
+}
+
+bool SystemInformation::DoesCPUSupportCPUID()
+{
+  return this->Implementation->DoesCPUSupportCPUID();
+}
+
+// Retrieve memory information in megabyte.
+size_t SystemInformation::GetTotalVirtualMemory()
+{
+  return this->Implementation->GetTotalVirtualMemory();
+}
+
+size_t SystemInformation::GetAvailableVirtualMemory()
+{
+  return this->Implementation->GetAvailableVirtualMemory();
+}
+
+size_t SystemInformation::GetTotalPhysicalMemory()
+{
+  return this->Implementation->GetTotalPhysicalMemory();
+}
+
+size_t SystemInformation::GetAvailablePhysicalMemory()
+{
+  return this->Implementation->GetAvailablePhysicalMemory();
+}
+
+std::string SystemInformation::GetMemoryDescription(
+  const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
+{
+  std::ostringstream oss;
+  oss << "Host Total: " << iostreamLongLong(this->GetHostMemoryTotal())
+      << " KiB, Host Available: "
+      << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName))
+      << " KiB, Process Available: "
+      << iostreamLongLong(this->GetProcMemoryAvailable(hostLimitEnvVarName,
+                                                       procLimitEnvVarName))
+      << " KiB";
+  return oss.str();
+}
+
+// host memory info in units of KiB.
+SystemInformation::LongLong SystemInformation::GetHostMemoryTotal()
+{
+  return this->Implementation->GetHostMemoryTotal();
+}
+
+SystemInformation::LongLong SystemInformation::GetHostMemoryAvailable(
+  const char* hostLimitEnvVarName)
+{
+  return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName);
+}
+
+SystemInformation::LongLong SystemInformation::GetHostMemoryUsed()
+{
+  return this->Implementation->GetHostMemoryUsed();
+}
+
+// process memory info in units of KiB.
+SystemInformation::LongLong SystemInformation::GetProcMemoryAvailable(
+  const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
+{
+  return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName,
+                                                      procLimitEnvVarName);
+}
+
+SystemInformation::LongLong SystemInformation::GetProcMemoryUsed()
+{
+  return this->Implementation->GetProcMemoryUsed();
+}
+
+double SystemInformation::GetLoadAverage()
+{
+  return this->Implementation->GetLoadAverage();
+}
+
+SystemInformation::LongLong SystemInformation::GetProcessId()
+{
+  return this->Implementation->GetProcessId();
+}
+
+void SystemInformation::SetStackTraceOnError(int enable)
+{
+  SystemInformationImplementation::SetStackTraceOnError(enable);
+}
+
+std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
+{
+  return SystemInformationImplementation::GetProgramStack(firstFrame,
+                                                          wholePath);
+}
+
+/** Run the different checks */
+void SystemInformation::RunCPUCheck()
+{
+  this->Implementation->RunCPUCheck();
+}
+
+void SystemInformation::RunOSCheck()
+{
+  this->Implementation->RunOSCheck();
+}
+
+void SystemInformation::RunMemoryCheck()
+{
+  this->Implementation->RunMemoryCheck();
+}
+
+// --------------------------------------------------------------
+// SystemInformationImplementation starts here
+
+#define STORE_TLBCACHE_INFO(x, y) x = (x < (y)) ? (y) : x
+#define TLBCACHE_INFO_UNITS (15)
+#define CLASSICAL_CPU_FREQ_LOOP 10000000
+#define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31
+
+#define MMX_FEATURE 0x00000001
+#define MMX_PLUS_FEATURE 0x00000002
+#define SSE_FEATURE 0x00000004
+#define SSE2_FEATURE 0x00000008
+#define AMD_3DNOW_FEATURE 0x00000010
+#define AMD_3DNOW_PLUS_FEATURE 0x00000020
+#define IA64_FEATURE 0x00000040
+#define MP_CAPABLE 0x00000080
+#define HYPERTHREAD_FEATURE 0x00000100
+#define SERIALNUMBER_FEATURE 0x00000200
+#define APIC_FEATURE 0x00000400
+#define SSE_FP_FEATURE 0x00000800
+#define SSE_MMX_FEATURE 0x00001000
+#define CMOV_FEATURE 0x00002000
+#define MTRR_FEATURE 0x00004000
+#define L1CACHE_FEATURE 0x00008000
+#define L2CACHE_FEATURE 0x00010000
+#define L3CACHE_FEATURE 0x00020000
+#define ACPI_FEATURE 0x00040000
+#define THERMALMONITOR_FEATURE 0x00080000
+#define TEMPSENSEDIODE_FEATURE 0x00100000
+#define FREQUENCYID_FEATURE 0x00200000
+#define VOLTAGEID_FREQUENCY 0x00400000
+
+// Status Flag
+#define HT_NOT_CAPABLE 0
+#define HT_ENABLED 1
+#define HT_DISABLED 2
+#define HT_SUPPORTED_NOT_ENABLED 3
+#define HT_CANNOT_DETECT 4
+
+// EDX[28]  Bit 28 is set if HT is supported
+#define HT_BIT 0x10000000
+
+// EAX[11:8] Bit 8-11 contains family processor ID.
+#define FAMILY_ID 0x0F00
+#define PENTIUM4_ID 0x0F00
+// EAX[23:20] Bit 20-23 contains extended family processor ID
+#define EXT_FAMILY_ID 0x0F00000
+// EBX[23:16] Bit 16-23 in ebx contains the number of logical
+#define NUM_LOGICAL_BITS 0x00FF0000
+// processors per physical processor when execute cpuid with
+// eax set to 1
+// EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
+#define INITIAL_APIC_ID_BITS 0xFF000000
+// initial APIC ID for the processor this code is running on.
+// Default value = 0xff if HT is not supported
+
+// Hide implementation details in an anonymous namespace.
+namespace {
+// *****************************************************************************
+#if defined(__linux) || defined(__APPLE__)
+int LoadLines(FILE* file, std::vector<std::string>& lines)
+{
+  // Load each line in the given file into a the vector.
+  int nRead = 0;
+  const int bufSize = 1024;
+  char buf[bufSize] = { '\0' };
+  while (!feof(file) && !ferror(file)) {
+    errno = 0;
+    if (fgets(buf, bufSize, file) == 0) {
+      if (ferror(file) && (errno == EINTR)) {
+        clearerr(file);
+      }
+      continue;
+    }
+    char* pBuf = buf;
+    while (*pBuf) {
+      if (*pBuf == '\n')
+        *pBuf = '\0';
+      pBuf += 1;
+    }
+    lines.push_back(buf);
+    ++nRead;
+  }
+  if (ferror(file)) {
+    return 0;
+  }
+  return nRead;
+}
+
+#if defined(__linux)
+// *****************************************************************************
+int LoadLines(const char* fileName, std::vector<std::string>& lines)
+{
+  FILE* file = fopen(fileName, "r");
+  if (file == 0) {
+    return 0;
+  }
+  int nRead = LoadLines(file, lines);
+  fclose(file);
+  return nRead;
+}
+#endif
+
+// ****************************************************************************
+template <typename T>
+int NameValue(std::vector<std::string>& lines, std::string name, T& value)
+{
+  size_t nLines = lines.size();
+  for (size_t i = 0; i < nLines; ++i) {
+    size_t at = lines[i].find(name);
+    if (at == std::string::npos) {
+      continue;
+    }
+    std::istringstream is(lines[i].substr(at + name.size()));
+    is >> value;
+    return 0;
+  }
+  return -1;
+}
+#endif
+
+#if defined(__linux)
+// ****************************************************************************
+template <typename T>
+int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values)
+{
+  std::vector<std::string> fields;
+  if (!LoadLines(fileName, fields)) {
+    return -1;
+  }
+  int i = 0;
+  while (fieldNames[i] != NULL) {
+    int ierr = NameValue(fields, fieldNames[i], values[i]);
+    if (ierr) {
+      return -(i + 2);
+    }
+    i += 1;
+  }
+  return 0;
+}
+
+// ****************************************************************************
+template <typename T>
+int GetFieldFromFile(const char* fileName, const char* fieldName, T& value)
+{
+  const char* fieldNames[2] = { fieldName, NULL };
+  T values[1] = { T(0) };
+  int ierr = GetFieldsFromFile(fileName, fieldNames, values);
+  if (ierr) {
+    return ierr;
+  }
+  value = values[0];
+  return 0;
+}
+#endif
+
+// ****************************************************************************
+#if defined(__APPLE__)
+template <typename T>
+int GetFieldsFromCommand(const char* command, const char** fieldNames,
+                         T* values)
+{
+  FILE* file = popen(command, "r");
+  if (file == 0) {
+    return -1;
+  }
+  std::vector<std::string> fields;
+  int nl = LoadLines(file, fields);
+  pclose(file);
+  if (nl == 0) {
+    return -1;
+  }
+  int i = 0;
+  while (fieldNames[i] != NULL) {
+    int ierr = NameValue(fields, fieldNames[i], values[i]);
+    if (ierr) {
+      return -(i + 2);
+    }
+    i += 1;
+  }
+  return 0;
+}
+#endif
+
+// ****************************************************************************
+#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo,
+                             void* /*sigContext*/)
+{
+#if defined(__linux) || defined(__APPLE__)
+  std::ostringstream oss;
+  oss << std::endl
+      << "========================================================="
+      << std::endl
+      << "Process id " << getpid() << " ";
+  switch (sigNo) {
+    case SIGINT:
+      oss << "Caught SIGINT";
+      break;
+
+    case SIGTERM:
+      oss << "Caught SIGTERM";
+      break;
+
+    case SIGABRT:
+      oss << "Caught SIGABRT";
+      break;
+
+    case SIGFPE:
+      oss << "Caught SIGFPE at " << (sigInfo->si_addr == 0 ? "0x" : "")
+          << sigInfo->si_addr << " ";
+      switch (sigInfo->si_code) {
+#if defined(FPE_INTDIV)
+        case FPE_INTDIV:
+          oss << "integer division by zero";
+          break;
+#endif
+
+#if defined(FPE_INTOVF)
+        case FPE_INTOVF:
+          oss << "integer overflow";
+          break;
+#endif
+
+        case FPE_FLTDIV:
+          oss << "floating point divide by zero";
+          break;
+
+        case FPE_FLTOVF:
+          oss << "floating point overflow";
+          break;
+
+        case FPE_FLTUND:
+          oss << "floating point underflow";
+          break;
+
+        case FPE_FLTRES:
+          oss << "floating point inexact result";
+          break;
+
+        case FPE_FLTINV:
+          oss << "floating point invalid operation";
+          break;
+
+#if defined(FPE_FLTSUB)
+        case FPE_FLTSUB:
+          oss << "floating point subscript out of range";
+          break;
+#endif
+
+        default:
+          oss << "code " << sigInfo->si_code;
+          break;
+      }
+      break;
+
+    case SIGSEGV:
+      oss << "Caught SIGSEGV at " << (sigInfo->si_addr == 0 ? "0x" : "")
+          << sigInfo->si_addr << " ";
+      switch (sigInfo->si_code) {
+        case SEGV_MAPERR:
+          oss << "address not mapped to object";
+          break;
+
+        case SEGV_ACCERR:
+          oss << "invalid permission for mapped object";
+          break;
+
+        default:
+          oss << "code " << sigInfo->si_code;
+          break;
+      }
+      break;
+
+    case SIGBUS:
+      oss << "Caught SIGBUS at " << (sigInfo->si_addr == 0 ? "0x" : "")
+          << sigInfo->si_addr << " ";
+      switch (sigInfo->si_code) {
+        case BUS_ADRALN:
+          oss << "invalid address alignment";
+          break;
+
+#if defined(BUS_ADRERR)
+        case BUS_ADRERR:
+          oss << "nonexistent physical address";
+          break;
+#endif
+
+#if defined(BUS_OBJERR)
+        case BUS_OBJERR:
+          oss << "object-specific hardware error";
+          break;
+#endif
+
+#if defined(BUS_MCEERR_AR)
+        case BUS_MCEERR_AR:
+          oss << "Hardware memory error consumed on a machine check; action "
+                 "required.";
+          break;
+#endif
+
+#if defined(BUS_MCEERR_AO)
+        case BUS_MCEERR_AO:
+          oss << "Hardware memory error detected in process but not consumed; "
+                 "action optional.";
+          break;
+#endif
+
+        default:
+          oss << "code " << sigInfo->si_code;
+          break;
+      }
+      break;
+
+    case SIGILL:
+      oss << "Caught SIGILL at " << (sigInfo->si_addr == 0 ? "0x" : "")
+          << sigInfo->si_addr << " ";
+      switch (sigInfo->si_code) {
+        case ILL_ILLOPC:
+          oss << "illegal opcode";
+          break;
+
+#if defined(ILL_ILLOPN)
+        case ILL_ILLOPN:
+          oss << "illegal operand";
+          break;
+#endif
+
+#if defined(ILL_ILLADR)
+        case ILL_ILLADR:
+          oss << "illegal addressing mode.";
+          break;
+#endif
+
+        case ILL_ILLTRP:
+          oss << "illegal trap";
+          break;
+
+        case ILL_PRVOPC:
+          oss << "privileged opcode";
+          break;
+
+#if defined(ILL_PRVREG)
+        case ILL_PRVREG:
+          oss << "privileged register";
+          break;
+#endif
+
+#if defined(ILL_COPROC)
+        case ILL_COPROC:
+          oss << "co-processor error";
+          break;
+#endif
+
+#if defined(ILL_BADSTK)
+        case ILL_BADSTK:
+          oss << "internal stack error";
+          break;
+#endif
+
+        default:
+          oss << "code " << sigInfo->si_code;
+          break;
+      }
+      break;
+
+    default:
+      oss << "Caught " << sigNo << " code " << sigInfo->si_code;
+      break;
+  }
+  oss << std::endl
+      << "Program Stack:" << std::endl
+      << SystemInformationImplementation::GetProgramStack(2, 0)
+      << "========================================================="
+      << std::endl;
+  std::cerr << oss.str() << std::endl;
+
+  // restore the previously registered handlers
+  // and abort
+  SystemInformationImplementation::SetStackTraceOnError(0);
+  abort();
+#else
+  // avoid warning C4100
+  (void)sigNo;
+  (void)sigInfo;
+#endif
+}
+#endif
+
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+#define safes(_arg) ((_arg) ? (_arg) : "???")
+
+// Description:
+// A container for symbol properties. Each instance
+// must be Initialized.
+class SymbolProperties
+{
+public:
+  SymbolProperties();
+
+  // Description:
+  // The SymbolProperties instance must be initialized by
+  // passing a stack address.
+  void Initialize(void* address);
+
+  // Description:
+  // Get the symbol's stack address.
+  void* GetAddress() const { return this->Address; }
+
+  // Description:
+  // If not set paths will be removed. eg, from a binary
+  // or source file.
+  void SetReportPath(int rp) { this->ReportPath = rp; }
+
+  // Description:
+  // Set/Get the name of the binary file that the symbol
+  // is found in.
+  void SetBinary(const char* binary) { this->Binary = safes(binary); }
+
+  std::string GetBinary() const;
+
+  // Description:
+  // Set the name of the function that the symbol is found in.
+  // If c++ demangling is supported it will be demangled.
+  void SetFunction(const char* function)
+  {
+    this->Function = this->Demangle(function);
+  }
+
+  std::string GetFunction() const { return this->Function; }
+
+  // Description:
+  // Set/Get the name of the source file where the symbol
+  // is defined.
+  void SetSourceFile(const char* sourcefile)
+  {
+    this->SourceFile = safes(sourcefile);
+  }
+
+  std::string GetSourceFile() const
+  {
+    return this->GetFileName(this->SourceFile);
+  }
+
+  // Description:
+  // Set/Get the line number where the symbol is defined
+  void SetLineNumber(long linenumber) { this->LineNumber = linenumber; }
+  long GetLineNumber() const { return this->LineNumber; }
+
+  // Description:
+  // Set the address where the biinary image is mapped
+  // into memory.
+  void SetBinaryBaseAddress(void* address)
+  {
+    this->BinaryBaseAddress = address;
+  }
+
+private:
+  void* GetRealAddress() const
+  {
+    return (void*)((char*)this->Address - (char*)this->BinaryBaseAddress);
+  }
+
+  std::string GetFileName(const std::string& path) const;
+  std::string Demangle(const char* symbol) const;
+
+private:
+  std::string Binary;
+  void* BinaryBaseAddress;
+  void* Address;
+  std::string SourceFile;
+  std::string Function;
+  long LineNumber;
+  int ReportPath;
+};
+
+// --------------------------------------------------------------------------
+std::ostream& operator<<(std::ostream& os, const SymbolProperties& sp)
+{
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+  os << std::hex << sp.GetAddress() << " : " << sp.GetFunction() << " [("
+     << sp.GetBinary() << ") " << sp.GetSourceFile() << ":" << std::dec
+     << sp.GetLineNumber() << "]";
+#elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+  void* addr = sp.GetAddress();
+  char** syminfo = backtrace_symbols(&addr, 1);
+  os << safes(syminfo[0]);
+  free(syminfo);
+#else
+  (void)os;
+  (void)sp;
+#endif
+  return os;
+}
+
+// --------------------------------------------------------------------------
+SymbolProperties::SymbolProperties()
+{
+  // not using an initializer list
+  // to avoid some PGI compiler warnings
+  this->SetBinary("???");
+  this->SetBinaryBaseAddress(NULL);
+  this->Address = NULL;
+  this->SetSourceFile("???");
+  this->SetFunction("???");
+  this->SetLineNumber(-1);
+  this->SetReportPath(0);
+  // avoid PGI compiler warnings
+  this->GetRealAddress();
+  this->GetFunction();
+  this->GetSourceFile();
+  this->GetLineNumber();
+}
+
+// --------------------------------------------------------------------------
+std::string SymbolProperties::GetFileName(const std::string& path) const
+{
+  std::string file(path);
+  if (!this->ReportPath) {
+    size_t at = file.rfind("/");
+    if (at != std::string::npos) {
+      file = file.substr(at + 1, std::string::npos);
+    }
+  }
+  return file;
+}
+
+// --------------------------------------------------------------------------
+std::string SymbolProperties::GetBinary() const
+{
+// only linux has proc fs
+#if defined(__linux__)
+  if (this->Binary == "/proc/self/exe") {
+    std::string binary;
+    char buf[1024] = { '\0' };
+    ssize_t ll = 0;
+    if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0) {
+      buf[ll] = '\0';
+      binary = buf;
+    } else {
+      binary = "/proc/self/exe";
+    }
+    return this->GetFileName(binary);
+  }
+#endif
+  return this->GetFileName(this->Binary);
+}
+
+// --------------------------------------------------------------------------
+std::string SymbolProperties::Demangle(const char* symbol) const
+{
+  std::string result = safes(symbol);
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
+  int status = 0;
+  size_t bufferLen = 1024;
+  char* buffer = (char*)malloc(1024);
+  char* demangledSymbol =
+    abi::__cxa_demangle(symbol, buffer, &bufferLen, &status);
+  if (!status) {
+    result = demangledSymbol;
+  }
+  free(buffer);
+#else
+  (void)symbol;
+#endif
+  return result;
+}
+
+// --------------------------------------------------------------------------
+void SymbolProperties::Initialize(void* address)
+{
+  this->Address = address;
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+  // first fallback option can demangle c++ functions
+  Dl_info info;
+  int ierr = dladdr(this->Address, &info);
+  if (ierr && info.dli_sname && info.dli_saddr) {
+    this->SetBinary(info.dli_fname);
+    this->SetFunction(info.dli_sname);
+  }
+#else
+// second fallback use builtin backtrace_symbols
+// to decode the bactrace.
+#endif
+}
+#endif // don't define this class if we're not using it
+
+// --------------------------------------------------------------------------
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes
+#endif
+#if defined(_MSC_VER) && _MSC_VER < 1310
+#undef KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes
+#endif
+#if defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes)
+double calculateCPULoad(unsigned __int64 idleTicks,
+                        unsigned __int64 totalTicks)
+{
+  static double previousLoad = -0.0;
+  static unsigned __int64 previousIdleTicks = 0;
+  static unsigned __int64 previousTotalTicks = 0;
+
+  unsigned __int64 const idleTicksSinceLastTime =
+    idleTicks - previousIdleTicks;
+  unsigned __int64 const totalTicksSinceLastTime =
+    totalTicks - previousTotalTicks;
+
+  double load;
+  if (previousTotalTicks == 0 || totalTicksSinceLastTime == 0) {
+    // No new information.  Use previous result.
+    load = previousLoad;
+  } else {
+    // Calculate load since last time.
+    load = 1.0 - double(idleTicksSinceLastTime) / totalTicksSinceLastTime;
+
+    // Smooth if possible.
+    if (previousLoad > 0) {
+      load = 0.25 * load + 0.75 * previousLoad;
+    }
+  }
+
+  previousLoad = load;
+  previousIdleTicks = idleTicks;
+  previousTotalTicks = totalTicks;
+
+  return load;
+}
+
+unsigned __int64 fileTimeToUInt64(FILETIME const& ft)
+{
+  LARGE_INTEGER out;
+  out.HighPart = ft.dwHighDateTime;
+  out.LowPart = ft.dwLowDateTime;
+  return out.QuadPart;
+}
+#endif
+
+} // anonymous namespace
+
+SystemInformationImplementation::SystemInformationImplementation()
+{
+  this->TotalVirtualMemory = 0;
+  this->AvailableVirtualMemory = 0;
+  this->TotalPhysicalMemory = 0;
+  this->AvailablePhysicalMemory = 0;
+  this->CurrentPositionInFile = 0;
+  this->ChipManufacturer = UnknownManufacturer;
+  memset(&this->Features, 0, sizeof(CPUFeatures));
+  this->ChipID.Type = 0;
+  this->ChipID.Family = 0;
+  this->ChipID.Model = 0;
+  this->ChipID.Revision = 0;
+  this->ChipID.ExtendedFamily = 0;
+  this->ChipID.ExtendedModel = 0;
+  this->CPUSpeedInMHz = 0;
+  this->NumberOfLogicalCPU = 0;
+  this->NumberOfPhysicalCPU = 0;
+  this->OSName = "";
+  this->Hostname = "";
+  this->OSRelease = "";
+  this->OSVersion = "";
+  this->OSPlatform = "";
+  this->OSIs64Bit = (sizeof(void*) == 8);
+}
+
+SystemInformationImplementation::~SystemInformationImplementation()
+{
+}
+
+void SystemInformationImplementation::RunCPUCheck()
+{
+#ifdef _WIN32
+  // Check to see if this processor supports CPUID.
+  bool supportsCPUID = DoesCPUSupportCPUID();
+
+  if (supportsCPUID) {
+    // Retrieve the CPU details.
+    RetrieveCPUIdentity();
+    this->FindManufacturer();
+    RetrieveCPUFeatures();
+  }
+
+  // These two may be called without support for the CPUID instruction.
+  // (But if the instruction is there, they should be called *after*
+  // the above call to RetrieveCPUIdentity... that's why the two if
+  // blocks exist with the same "if (supportsCPUID)" logic...
+  //
+  if (!RetrieveCPUClockSpeed()) {
+    RetrieveClassicalCPUClockSpeed();
+  }
+
+  if (supportsCPUID) {
+    // Retrieve cache information.
+    if (!RetrieveCPUCacheDetails()) {
+      RetrieveClassicalCPUCacheDetails();
+    }
+
+    // Retrieve the extended CPU details.
+    if (!RetrieveExtendedCPUIdentity()) {
+      RetrieveClassicalCPUIdentity();
+    }
+
+    RetrieveExtendedCPUFeatures();
+    RetrieveCPUPowerManagement();
+
+    // Now attempt to retrieve the serial number (if possible).
+    RetrieveProcessorSerialNumber();
+  }
+
+  this->CPUCountWindows();
+
+#elif defined(__APPLE__)
+  this->ParseSysCtl();
+#elif defined(__SVR4) && defined(__sun)
+  this->QuerySolarisProcessor();
+#elif defined(__HAIKU__)
+  this->QueryHaikuInfo();
+#elif defined(__QNX__)
+  this->QueryQNXProcessor();
+#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||  \
+  defined(__DragonFly__)
+  this->QueryBSDProcessor();
+#elif defined(__hpux)
+  this->QueryHPUXProcessor();
+#elif defined(__linux) || defined(__CYGWIN__)
+  this->RetreiveInformationFromCpuInfoFile();
+#else
+  this->QueryProcessor();
+#endif
+}
+
+void SystemInformationImplementation::RunOSCheck()
+{
+  this->QueryOSInformation();
+}
+
+void SystemInformationImplementation::RunMemoryCheck()
+{
+#if defined(__APPLE__)
+  this->ParseSysCtl();
+#elif defined(__SVR4) && defined(__sun)
+  this->QuerySolarisMemory();
+#elif defined(__HAIKU__)
+  this->QueryHaikuInfo();
+#elif defined(__QNX__)
+  this->QueryQNXMemory();
+#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||  \
+  defined(__DragonFly__)
+  this->QueryBSDMemory();
+#elif defined(__CYGWIN__)
+  this->QueryCygwinMemory();
+#elif defined(_WIN32)
+  this->QueryWindowsMemory();
+#elif defined(__hpux)
+  this->QueryHPUXMemory();
+#elif defined(__linux)
+  this->QueryLinuxMemory();
+#elif defined(_AIX)
+  this->QueryAIXMemory();
+#else
+  this->QueryMemory();
+#endif
+}
+
+/** Get the vendor string */
+const char* SystemInformationImplementation::GetVendorString()
+{
+  return this->ChipID.Vendor.c_str();
+}
+
+/** Get the OS Name */
+const char* SystemInformationImplementation::GetOSName()
+{
+  return this->OSName.c_str();
+}
+
+/** Get the hostname */
+const char* SystemInformationImplementation::GetHostname()
+{
+  if (this->Hostname.empty()) {
+    this->Hostname = "localhost";
+#if defined(_WIN32)
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    char name[255];
+    wVersionRequested = MAKEWORD(2, 0);
+    if (WSAStartup(wVersionRequested, &wsaData) == 0) {
+      gethostname(name, sizeof(name));
+      WSACleanup();
+    }
+    this->Hostname = name;
+#else
+    struct utsname unameInfo;
+    int errorFlag = uname(&unameInfo);
+    if (errorFlag == 0) {
+      this->Hostname = unameInfo.nodename;
+    }
+#endif
+  }
+  return this->Hostname.c_str();
+}
+
+/** Get the FQDN */
+int SystemInformationImplementation::GetFullyQualifiedDomainName(
+  std::string& fqdn)
+{
+  // in the event of absolute failure return localhost.
+  fqdn = "localhost";
+
+#if defined(_WIN32)
+  int ierr;
+  // TODO - a more robust implementation for windows, see comments
+  // in unix implementation.
+  WSADATA wsaData;
+  WORD ver = MAKEWORD(2, 0);
+  ierr = WSAStartup(ver, &wsaData);
+  if (ierr) {
+    return -1;
+  }
+
+  char base[256] = { '\0' };
+  ierr = gethostname(base, 256);
+  if (ierr) {
+    WSACleanup();
+    return -2;
+  }
+  fqdn = base;
+
+  HOSTENT* hent = gethostbyname(base);
+  if (hent) {
+    fqdn = hent->h_name;
+  }
+
+  WSACleanup();
+  return 0;
+
+#elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN)
+  // gethostname typical returns an alias for loopback interface
+  // we want the fully qualified domain name. Because there are
+  // any number of interfaces on this system we look for the
+  // first of these that contains the name returned by gethostname
+  // and is longer. failing that we return gethostname and indicate
+  // with a failure code. Return of a failure code is not necessarilly
+  // an indication of an error. for instance gethostname may return
+  // the fully qualified domain name, or there may not be one if the
+  // system lives on a private network such as in the case of a cluster
+  // node.
+
+  int ierr = 0;
+  char base[NI_MAXHOST];
+  ierr = gethostname(base, NI_MAXHOST);
+  if (ierr) {
+    return -1;
+  }
+  size_t baseSize = strlen(base);
+  fqdn = base;
+
+  struct ifaddrs* ifas;
+  struct ifaddrs* ifa;
+  ierr = getifaddrs(&ifas);
+  if (ierr) {
+    return -2;
+  }
+
+  for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
+    int fam = ifa->ifa_addr ? ifa->ifa_addr->sa_family : -1;
+    // Skip Loopback interfaces
+    if (((fam == AF_INET) || (fam == AF_INET6)) &&
+        !(ifa->ifa_flags & IFF_LOOPBACK)) {
+      char host[NI_MAXHOST] = { '\0' };
+
+      const size_t addrlen = (fam == AF_INET ? sizeof(struct sockaddr_in)
+                                             : sizeof(struct sockaddr_in6));
+
+      ierr = getnameinfo(ifa->ifa_addr, static_cast<socklen_t>(addrlen), host,
+                         NI_MAXHOST, NULL, 0, NI_NAMEREQD);
+      if (ierr) {
+        // don't report the failure now since we may succeed on another
+        // interface. If all attempts fail then return the failure code.
+        ierr = -3;
+        continue;
+      }
+
+      std::string candidate = host;
+      if ((candidate.find(base) != std::string::npos) &&
+          baseSize < candidate.size()) {
+        // success, stop now.
+        ierr = 0;
+        fqdn = candidate;
+        break;
+      }
+    }
+  }
+  freeifaddrs(ifas);
+
+  return ierr;
+#else
+  /* TODO: Implement on more platforms.  */
+  fqdn = this->GetHostname();
+  return -1;
+#endif
+}
+
+/** Get the OS release */
+const char* SystemInformationImplementation::GetOSRelease()
+{
+  return this->OSRelease.c_str();
+}
+
+/** Get the OS version */
+const char* SystemInformationImplementation::GetOSVersion()
+{
+  return this->OSVersion.c_str();
+}
+
+/** Get the OS platform */
+const char* SystemInformationImplementation::GetOSPlatform()
+{
+  return this->OSPlatform.c_str();
+}
+
+/** Get the vendor ID */
+const char* SystemInformationImplementation::GetVendorID()
+{
+  // Return the vendor ID.
+  switch (this->ChipManufacturer) {
+    case Intel:
+      return "Intel Corporation";
+    case AMD:
+      return "Advanced Micro Devices";
+    case NSC:
+      return "National Semiconductor";
+    case Cyrix:
+      return "Cyrix Corp., VIA Inc.";
+    case NexGen:
+      return "NexGen Inc., Advanced Micro Devices";
+    case IDT:
+      return "IDT\\Centaur, Via Inc.";
+    case UMC:
+      return "United Microelectronics Corp.";
+    case Rise:
+      return "Rise";
+    case Transmeta:
+      return "Transmeta";
+    case Sun:
+      return "Sun Microelectronics";
+    case IBM:
+      return "IBM";
+    case Motorola:
+      return "Motorola";
+    case HP:
+      return "Hewlett-Packard";
+    case UnknownManufacturer:
+    default:
+      return "Unknown Manufacturer";
+  }
+}
+
+/** Return the type ID of the CPU */
+std::string SystemInformationImplementation::GetTypeID()
+{
+  std::ostringstream str;
+  str << this->ChipID.Type;
+  return str.str();
+}
+
+/** Return the family of the CPU present */
+std::string SystemInformationImplementation::GetFamilyID()
+{
+  std::ostringstream str;
+  str << this->ChipID.Family;
+  return str.str();
+}
+
+// Return the model of CPU present */
+std::string SystemInformationImplementation::GetModelID()
+{
+  std::ostringstream str;
+  str << this->ChipID.Model;
+  return str.str();
+}
+
+// Return the model name of CPU present */
+std::string SystemInformationImplementation::GetModelName()
+{
+  return this->ChipID.ModelName;
+}
+
+/** Return the stepping code of the CPU present. */
+std::string SystemInformationImplementation::GetSteppingCode()
+{
+  std::ostringstream str;
+  str << this->ChipID.Revision;
+  return str.str();
+}
+
+/** Return the stepping code of the CPU present. */
+const char* SystemInformationImplementation::GetExtendedProcessorName()
+{
+  return this->ChipID.ProcessorName.c_str();
+}
+
+/** Return the serial number of the processor
+ *  in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */
+const char* SystemInformationImplementation::GetProcessorSerialNumber()
+{
+  return this->ChipID.SerialNumber.c_str();
+}
+
+/** Return the logical processors per physical */
+unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical()
+{
+  return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical;
+}
+
+/** Return the processor clock frequency. */
+float SystemInformationImplementation::GetProcessorClockFrequency()
+{
+  return this->CPUSpeedInMHz;
+}
+
+/**  Return the APIC ID. */
+int SystemInformationImplementation::GetProcessorAPICID()
+{
+  return this->Features.ExtendedFeatures.APIC_ID;
+}
+
+/** Return the L1 cache size. */
+int SystemInformationImplementation::GetProcessorCacheSize()
+{
+  return this->Features.L1CacheSize;
+}
+
+/** Return the chosen cache size. */
+int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID)
+{
+  switch (dwCacheID) {
+    case L1CACHE_FEATURE:
+      return this->Features.L1CacheSize;
+    case L2CACHE_FEATURE:
+      return this->Features.L2CacheSize;
+    case L3CACHE_FEATURE:
+      return this->Features.L3CacheSize;
+  }
+  return -1;
+}
+
+bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature)
+{
+  bool bHasFeature = false;
+
+  // Check for MMX instructions.
+  if (((dwFeature & MMX_FEATURE) != 0) && this->Features.HasMMX)
+    bHasFeature = true;
+
+  // Check for MMX+ instructions.
+  if (((dwFeature & MMX_PLUS_FEATURE) != 0) &&
+      this->Features.ExtendedFeatures.HasMMXPlus)
+    bHasFeature = true;
+
+  // Check for SSE FP instructions.
+  if (((dwFeature & SSE_FEATURE) != 0) && this->Features.HasSSE)
+    bHasFeature = true;
+
+  // Check for SSE FP instructions.
+  if (((dwFeature & SSE_FP_FEATURE) != 0) && this->Features.HasSSEFP)
+    bHasFeature = true;
+
+  // Check for SSE MMX instructions.
+  if (((dwFeature & SSE_MMX_FEATURE) != 0) &&
+      this->Features.ExtendedFeatures.HasSSEMMX)
+    bHasFeature = true;
+
+  // Check for SSE2 instructions.
+  if (((dwFeature & SSE2_FEATURE) != 0) && this->Features.HasSSE2)
+    bHasFeature = true;
+
+  // Check for 3DNow! instructions.
+  if (((dwFeature & AMD_3DNOW_FEATURE) != 0) &&
+      this->Features.ExtendedFeatures.Has3DNow)
+    bHasFeature = true;
+
+  // Check for 3DNow+ instructions.
+  if (((dwFeature & AMD_3DNOW_PLUS_FEATURE) != 0) &&
+      this->Features.ExtendedFeatures.Has3DNowPlus)
+    bHasFeature = true;
+
+  // Check for IA64 instructions.
+  if (((dwFeature & IA64_FEATURE) != 0) && this->Features.HasIA64)
+    bHasFeature = true;
+
+  // Check for MP capable.
+  if (((dwFeature & MP_CAPABLE) != 0) &&
+      this->Features.ExtendedFeatures.SupportsMP)
+    bHasFeature = true;
+
+  // Check for a serial number for the processor.
+  if (((dwFeature & SERIALNUMBER_FEATURE) != 0) && this->Features.HasSerial)
+    bHasFeature = true;
+
+  // Check for a local APIC in the processor.
+  if (((dwFeature & APIC_FEATURE) != 0) && this->Features.HasAPIC)
+    bHasFeature = true;
+
+  // Check for CMOV instructions.
+  if (((dwFeature & CMOV_FEATURE) != 0) && this->Features.HasCMOV)
+    bHasFeature = true;
+
+  // Check for MTRR instructions.
+  if (((dwFeature & MTRR_FEATURE) != 0) && this->Features.HasMTRR)
+    bHasFeature = true;
+
+  // Check for L1 cache size.
+  if (((dwFeature & L1CACHE_FEATURE) != 0) &&
+      (this->Features.L1CacheSize != -1))
+    bHasFeature = true;
+
+  // Check for L2 cache size.
+  if (((dwFeature & L2CACHE_FEATURE) != 0) &&
+      (this->Features.L2CacheSize != -1))
+    bHasFeature = true;
+
+  // Check for L3 cache size.
+  if (((dwFeature & L3CACHE_FEATURE) != 0) &&
+      (this->Features.L3CacheSize != -1))
+    bHasFeature = true;
+
+  // Check for ACPI capability.
+  if (((dwFeature & ACPI_FEATURE) != 0) && this->Features.HasACPI)
+    bHasFeature = true;
+
+  // Check for thermal monitor support.
+  if (((dwFeature & THERMALMONITOR_FEATURE) != 0) && this->Features.HasThermal)
+    bHasFeature = true;
+
+  // Check for temperature sensing diode support.
+  if (((dwFeature & TEMPSENSEDIODE_FEATURE) != 0) &&
+      this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode)
+    bHasFeature = true;
+
+  // Check for frequency ID support.
+  if (((dwFeature & FREQUENCYID_FEATURE) != 0) &&
+      this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID)
+    bHasFeature = true;
+
+  // Check for voltage ID support.
+  if (((dwFeature & VOLTAGEID_FREQUENCY) != 0) &&
+      this->Features.ExtendedFeatures.PowerManagement.HasVoltageID)
+    bHasFeature = true;
+
+  return bHasFeature;
+}
+
+void SystemInformationImplementation::Delay(unsigned int uiMS)
+{
+#ifdef _WIN32
+  LARGE_INTEGER Frequency, StartCounter, EndCounter;
+  __int64 x;
+
+  // Get the frequency of the high performance counter.
+  if (!QueryPerformanceFrequency(&Frequency))
+    return;
+  x = Frequency.QuadPart / 1000 * uiMS;
+
+  // Get the starting position of the counter.
+  QueryPerformanceCounter(&StartCounter);
+
+  do {
+    // Get the ending position of the counter.
+    QueryPerformanceCounter(&EndCounter);
+  } while (EndCounter.QuadPart - StartCounter.QuadPart < x);
+#endif
+  (void)uiMS;
+}
+
+bool SystemInformationImplementation::DoesCPUSupportCPUID()
+{
+#if USE_CPUID
+  int dummy[4] = { 0, 0, 0, 0 };
+
+#if USE_ASM_INSTRUCTIONS
+  return call_cpuid(0, dummy);
+#else
+  call_cpuid(0, dummy);
+  return dummy[0] || dummy[1] || dummy[2] || dummy[3];
+#endif
+#else
+  // Assume no cpuid instruction.
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::RetrieveCPUFeatures()
+{
+#if USE_CPUID
+  int cpuinfo[4] = { 0, 0, 0, 0 };
+
+  if (!call_cpuid(1, cpuinfo)) {
+    return false;
+  }
+
+  // Retrieve the features of CPU present.
+  this->Features.HasFPU =
+    ((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0
+  this->Features.HasTSC =
+    ((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4
+  this->Features.HasAPIC =
+    ((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9
+  this->Features.HasMTRR =
+    ((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12
+  this->Features.HasCMOV =
+    ((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15
+  this->Features.HasSerial =
+    ((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18
+  this->Features.HasACPI =
+    ((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22
+  this->Features.HasMMX =
+    ((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23
+  this->Features.HasSSE =
+    ((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25
+  this->Features.HasSSE2 =
+    ((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26
+  this->Features.HasThermal =
+    ((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29
+  this->Features.HasIA64 =
+    ((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30
+
+#if USE_ASM_INSTRUCTIONS
+  // Retrieve extended SSE capabilities if SSE is available.
+  if (this->Features.HasSSE) {
+
+    // Attempt to __try some SSE FP instructions.
+    __try {
+      // Perform: orps xmm0, xmm0
+      _asm
+      {
+        _emit 0x0f
+        _emit 0x56
+        _emit 0xc0
+      }
+
+      // SSE FP capable processor.
+      this->Features.HasSSEFP = true;
+    } __except (1) {
+      // bad instruction - processor or OS cannot handle SSE FP.
+      this->Features.HasSSEFP = false;
+    }
+  } else {
+    // Set the advanced SSE capabilities to not available.
+    this->Features.HasSSEFP = false;
+  }
+#else
+  this->Features.HasSSEFP = false;
+#endif
+
+  // Retrieve Intel specific extended features.
+  if (this->ChipManufacturer == Intel) {
+    bool SupportsSMT =
+      ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: SMT --> Bit 28
+
+    if ((SupportsSMT) && (this->Features.HasAPIC)) {
+      // Retrieve APIC information if there is one present.
+      this->Features.ExtendedFeatures.APIC_ID =
+        ((cpuinfo[1] & 0xFF000000) >> 24);
+    }
+  }
+
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+/** Find the manufacturer given the vendor id */
+void SystemInformationImplementation::FindManufacturer(
+  const std::string& family)
+{
+  if (this->ChipID.Vendor == "GenuineIntel")
+    this->ChipManufacturer = Intel; // Intel Corp.
+  else if (this->ChipID.Vendor == "UMC UMC UMC ")
+    this->ChipManufacturer = UMC; // United Microelectronics Corp.
+  else if (this->ChipID.Vendor == "AuthenticAMD")
+    this->ChipManufacturer = AMD; // Advanced Micro Devices
+  else if (this->ChipID.Vendor == "AMD ISBETTER")
+    this->ChipManufacturer = AMD; // Advanced Micro Devices (1994)
+  else if (this->ChipID.Vendor == "CyrixInstead")
+    this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
+  else if (this->ChipID.Vendor == "NexGenDriven")
+    this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD)
+  else if (this->ChipID.Vendor == "CentaurHauls")
+    this->ChipManufacturer = IDT; // IDT/Centaur (now VIA)
+  else if (this->ChipID.Vendor == "RiseRiseRise")
+    this->ChipManufacturer = Rise; // Rise
+  else if (this->ChipID.Vendor == "GenuineTMx86")
+    this->ChipManufacturer = Transmeta; // Transmeta
+  else if (this->ChipID.Vendor == "TransmetaCPU")
+    this->ChipManufacturer = Transmeta; // Transmeta
+  else if (this->ChipID.Vendor == "Geode By NSC")
+    this->ChipManufacturer = NSC; // National Semiconductor
+  else if (this->ChipID.Vendor == "Sun")
+    this->ChipManufacturer = Sun; // Sun Microelectronics
+  else if (this->ChipID.Vendor == "IBM")
+    this->ChipManufacturer = IBM; // IBM Microelectronics
+  else if (this->ChipID.Vendor == "Hewlett-Packard")
+    this->ChipManufacturer = HP; // Hewlett-Packard
+  else if (this->ChipID.Vendor == "Motorola")
+    this->ChipManufacturer = Motorola; // Motorola Microelectronics
+  else if (family.substr(0, 7) == "PA-RISC")
+    this->ChipManufacturer = HP; // Hewlett-Packard
+  else
+    this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUIdentity()
+{
+#if USE_CPUID
+  int localCPUVendor[4];
+  int localCPUSignature[4];
+
+  if (!call_cpuid(0, localCPUVendor)) {
+    return false;
+  }
+  if (!call_cpuid(1, localCPUSignature)) {
+    return false;
+  }
+
+  // Process the returned information.
+  //    ; eax = 0 --> eax: maximum value of CPUID instruction.
+  //    ;        ebx: part 1 of 3; CPU signature.
+  //    ;        edx: part 2 of 3; CPU signature.
+  //    ;        ecx: part 3 of 3; CPU signature.
+  char vbuf[13];
+  memcpy(&(vbuf[0]), &(localCPUVendor[1]), sizeof(int));
+  memcpy(&(vbuf[4]), &(localCPUVendor[3]), sizeof(int));
+  memcpy(&(vbuf[8]), &(localCPUVendor[2]), sizeof(int));
+  vbuf[12] = '\0';
+  this->ChipID.Vendor = vbuf;
+
+  // Retrieve the family of CPU present.
+  //    ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type,
+  //    bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision
+  //    ;        ebx: 31..24 - default APIC ID, 23..16 - logical processor ID,
+  //    15..8 - CFLUSH chunk size , 7..0 - brand ID
+  //    ;        edx: CPU feature flags
+  this->ChipID.ExtendedFamily =
+    ((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used
+  this->ChipID.ExtendedModel =
+    ((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used
+  this->ChipID.Type =
+    ((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used
+  this->ChipID.Family =
+    ((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used
+  this->ChipID.Model =
+    ((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used
+  this->ChipID.Revision =
+    ((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used
+
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUCacheDetails()
+{
+#if USE_CPUID
+  int L1Cache[4] = { 0, 0, 0, 0 };
+  int L2Cache[4] = { 0, 0, 0, 0 };
+
+  // Check to see if what we are about to do is supported...
+  if (RetrieveCPUExtendedLevelSupport(0x80000005)) {
+    if (!call_cpuid(0x80000005, L1Cache)) {
+      return false;
+    }
+    // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as
+    // data cache size from edx: bits 31..24.
+    this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24);
+    this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24);
+  } else {
+    // Store -1 to indicate the cache could not be queried.
+    this->Features.L1CacheSize = -1;
+  }
+
+  // Check to see if what we are about to do is supported...
+  if (RetrieveCPUExtendedLevelSupport(0x80000006)) {
+    if (!call_cpuid(0x80000006, L2Cache)) {
+      return false;
+    }
+    // Save the L2 unified cache size (in KB) from ecx: bits 31..16.
+    this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16);
+  } else {
+    // Store -1 to indicate the cache could not be queried.
+    this->Features.L2CacheSize = -1;
+  }
+
+  // Define L3 as being not present as we cannot test for it.
+  this->Features.L3CacheSize = -1;
+
+#endif
+
+  // Return failure if we cannot detect either cache with this method.
+  return ((this->Features.L1CacheSize == -1) &&
+          (this->Features.L2CacheSize == -1))
+    ? false
+    : true;
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
+{
+#if USE_CPUID
+  int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1,
+      L2Unified = -1, L3Unified = -1;
+  int TLBCacheData[4] = { 0, 0, 0, 0 };
+  int TLBPassCounter = 0;
+  int TLBCacheUnit = 0;
+
+  do {
+    if (!call_cpuid(2, TLBCacheData)) {
+      return false;
+    }
+
+    int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16);
+    (void)bob;
+    // Process the returned TLB and cache information.
+    for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter++) {
+      // First of all - decide which unit we are dealing with.
+      switch (nCounter) {
+        // eax: bits 8..15 : bits 16..23 : bits 24..31
+        case 0:
+          TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8);
+          break;
+        case 1:
+          TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16);
+          break;
+        case 2:
+          TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24);
+          break;
+
+        // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
+        case 3:
+          TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0);
+          break;
+        case 4:
+          TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8);
+          break;
+        case 5:
+          TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16);
+          break;
+        case 6:
+          TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24);
+          break;
+
+        // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
+        case 7:
+          TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0);
+          break;
+        case 8:
+          TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8);
+          break;
+        case 9:
+          TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16);
+          break;
+        case 10:
+          TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24);
+          break;
+
+        // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
+        case 11:
+          TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0);
+          break;
+        case 12:
+          TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8);
+          break;
+        case 13:
+          TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16);
+          break;
+        case 14:
+          TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24);
+          break;
+
+        // Default case - an error has occurred.
+        default:
+          return false;
+      }
+
+      // Now process the resulting unit to see what it means....
+      switch (TLBCacheUnit) {
+        case 0x00:
+          break;
+        case 0x01:
+          STORE_TLBCACHE_INFO(TLBCode, 4);
+          break;
+        case 0x02:
+          STORE_TLBCACHE_INFO(TLBCode, 4096);
+          break;
+        case 0x03:
+          STORE_TLBCACHE_INFO(TLBData, 4);
+          break;
+        case 0x04:
+          STORE_TLBCACHE_INFO(TLBData, 4096);
+          break;
+        case 0x06:
+          STORE_TLBCACHE_INFO(L1Code, 8);
+          break;
+        case 0x08:
+          STORE_TLBCACHE_INFO(L1Code, 16);
+          break;
+        case 0x0a:
+          STORE_TLBCACHE_INFO(L1Data, 8);
+          break;
+        case 0x0c:
+          STORE_TLBCACHE_INFO(L1Data, 16);
+          break;
+        case 0x10:
+          STORE_TLBCACHE_INFO(L1Data, 16);
+          break; // <-- FIXME: IA-64 Only
+        case 0x15:
+          STORE_TLBCACHE_INFO(L1Code, 16);
+          break; // <-- FIXME: IA-64 Only
+        case 0x1a:
+          STORE_TLBCACHE_INFO(L2Unified, 96);
+          break; // <-- FIXME: IA-64 Only
+        case 0x22:
+          STORE_TLBCACHE_INFO(L3Unified, 512);
+          break;
+        case 0x23:
+          STORE_TLBCACHE_INFO(L3Unified, 1024);
+          break;
+        case 0x25:
+          STORE_TLBCACHE_INFO(L3Unified, 2048);
+          break;
+        case 0x29:
+          STORE_TLBCACHE_INFO(L3Unified, 4096);
+          break;
+        case 0x39:
+          STORE_TLBCACHE_INFO(L2Unified, 128);
+          break;
+        case 0x3c:
+          STORE_TLBCACHE_INFO(L2Unified, 256);
+          break;
+        case 0x40:
+          STORE_TLBCACHE_INFO(L2Unified, 0);
+          break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4
+                 // core).
+        case 0x41:
+          STORE_TLBCACHE_INFO(L2Unified, 128);
+          break;
+        case 0x42:
+          STORE_TLBCACHE_INFO(L2Unified, 256);
+          break;
+        case 0x43:
+          STORE_TLBCACHE_INFO(L2Unified, 512);
+          break;
+        case 0x44:
+          STORE_TLBCACHE_INFO(L2Unified, 1024);
+          break;
+        case 0x45:
+          STORE_TLBCACHE_INFO(L2Unified, 2048);
+          break;
+        case 0x50:
+          STORE_TLBCACHE_INFO(TLBCode, 4096);
+          break;
+        case 0x51:
+          STORE_TLBCACHE_INFO(TLBCode, 4096);
+          break;
+        case 0x52:
+          STORE_TLBCACHE_INFO(TLBCode, 4096);
+          break;
+        case 0x5b:
+          STORE_TLBCACHE_INFO(TLBData, 4096);
+          break;
+        case 0x5c:
+          STORE_TLBCACHE_INFO(TLBData, 4096);
+          break;
+        case 0x5d:
+          STORE_TLBCACHE_INFO(TLBData, 4096);
+          break;
+        case 0x66:
+          STORE_TLBCACHE_INFO(L1Data, 8);
+          break;
+        case 0x67:
+          STORE_TLBCACHE_INFO(L1Data, 16);
+          break;
+        case 0x68:
+          STORE_TLBCACHE_INFO(L1Data, 32);
+          break;
+        case 0x70:
+          STORE_TLBCACHE_INFO(L1Trace, 12);
+          break;
+        case 0x71:
+          STORE_TLBCACHE_INFO(L1Trace, 16);
+          break;
+        case 0x72:
+          STORE_TLBCACHE_INFO(L1Trace, 32);
+          break;
+        case 0x77:
+          STORE_TLBCACHE_INFO(L1Code, 16);
+          break; // <-- FIXME: IA-64 Only
+        case 0x79:
+          STORE_TLBCACHE_INFO(L2Unified, 128);
+          break;
+        case 0x7a:
+          STORE_TLBCACHE_INFO(L2Unified, 256);
+          break;
+        case 0x7b:
+          STORE_TLBCACHE_INFO(L2Unified, 512);
+          break;
+        case 0x7c:
+          STORE_TLBCACHE_INFO(L2Unified, 1024);
+          break;
+        case 0x7e:
+          STORE_TLBCACHE_INFO(L2Unified, 256);
+          break;
+        case 0x81:
+          STORE_TLBCACHE_INFO(L2Unified, 128);
+          break;
+        case 0x82:
+          STORE_TLBCACHE_INFO(L2Unified, 256);
+          break;
+        case 0x83:
+          STORE_TLBCACHE_INFO(L2Unified, 512);
+          break;
+        case 0x84:
+          STORE_TLBCACHE_INFO(L2Unified, 1024);
+          break;
+        case 0x85:
+          STORE_TLBCACHE_INFO(L2Unified, 2048);
+          break;
+        case 0x88:
+          STORE_TLBCACHE_INFO(L3Unified, 2048);
+          break; // <-- FIXME: IA-64 Only
+        case 0x89:
+          STORE_TLBCACHE_INFO(L3Unified, 4096);
+          break; // <-- FIXME: IA-64 Only
+        case 0x8a:
+          STORE_TLBCACHE_INFO(L3Unified, 8192);
+          break; // <-- FIXME: IA-64 Only
+        case 0x8d:
+          STORE_TLBCACHE_INFO(L3Unified, 3096);
+          break; // <-- FIXME: IA-64 Only
+        case 0x90:
+          STORE_TLBCACHE_INFO(TLBCode, 262144);
+          break; // <-- FIXME: IA-64 Only
+        case 0x96:
+          STORE_TLBCACHE_INFO(TLBCode, 262144);
+          break; // <-- FIXME: IA-64 Only
+        case 0x9b:
+          STORE_TLBCACHE_INFO(TLBCode, 262144);
+          break; // <-- FIXME: IA-64 Only
+
+        // Default case - an error has occurred.
+        default:
+          return false;
+      }
+    }
+
+    // Increment the TLB pass counter.
+    TLBPassCounter++;
+  } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter);
+
+  // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
+  if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1)) {
+    this->Features.L1CacheSize = -1;
+  } else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1)) {
+    this->Features.L1CacheSize = L1Trace;
+  } else if ((L1Code != -1) && (L1Data == -1)) {
+    this->Features.L1CacheSize = L1Code;
+  } else if ((L1Code == -1) && (L1Data != -1)) {
+    this->Features.L1CacheSize = L1Data;
+  } else if ((L1Code != -1) && (L1Data != -1)) {
+    this->Features.L1CacheSize = L1Code + L1Data;
+  } else {
+    this->Features.L1CacheSize = -1;
+  }
+
+  // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
+  if (L2Unified == -1) {
+    this->Features.L2CacheSize = -1;
+  } else {
+    this->Features.L2CacheSize = L2Unified;
+  }
+
+  // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
+  if (L3Unified == -1) {
+    this->Features.L3CacheSize = -1;
+  } else {
+    this->Features.L3CacheSize = L3Unified;
+  }
+
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUClockSpeed()
+{
+  bool retrieved = false;
+
+#if defined(_WIN32)
+  unsigned int uiRepetitions = 1;
+  unsigned int uiMSecPerRepetition = 50;
+  __int64 i64Total = 0;
+  __int64 i64Overhead = 0;
+
+  // Check if the TSC implementation works at all
+  if (this->Features.HasTSC &&
+      GetCyclesDifference(SystemInformationImplementation::Delay,
+                          uiMSecPerRepetition) > 0) {
+    for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter++) {
+      i64Total += GetCyclesDifference(SystemInformationImplementation::Delay,
+                                      uiMSecPerRepetition);
+      i64Overhead += GetCyclesDifference(
+        SystemInformationImplementation::DelayOverhead, uiMSecPerRepetition);
+    }
+
+    // Calculate the MHz speed.
+    i64Total -= i64Overhead;
+    i64Total /= uiRepetitions;
+    i64Total /= uiMSecPerRepetition;
+    i64Total /= 1000;
+
+    // Save the CPU speed.
+    this->CPUSpeedInMHz = (float)i64Total;
+
+    retrieved = true;
+  }
+
+  // If RDTSC is not supported, we fallback to trying to read this value
+  // from the registry:
+  if (!retrieved) {
+    HKEY hKey = NULL;
+    LONG err =
+      RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                    L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
+                    KEY_READ, &hKey);
+
+    if (ERROR_SUCCESS == err) {
+      DWORD dwType = 0;
+      DWORD data = 0;
+      DWORD dwSize = sizeof(DWORD);
+
+      err =
+        RegQueryValueExW(hKey, L"~MHz", 0, &dwType, (LPBYTE)&data, &dwSize);
+
+      if (ERROR_SUCCESS == err) {
+        this->CPUSpeedInMHz = (float)data;
+        retrieved = true;
+      }
+
+      RegCloseKey(hKey);
+      hKey = NULL;
+    }
+  }
+#endif
+
+  return retrieved;
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
+{
+#if USE_ASM_INSTRUCTIONS
+  LARGE_INTEGER liStart, liEnd, liCountsPerSecond;
+  double dFrequency, dDifference;
+
+  // Attempt to get a starting tick count.
+  QueryPerformanceCounter(&liStart);
+
+  __try {
+    _asm {
+      mov eax, 0x80000000
+      mov ebx, CLASSICAL_CPU_FREQ_LOOP
+      Timer_Loop:
+      bsf ecx,eax
+      dec ebx
+      jnz Timer_Loop
+    }
+  } __except (1) {
+    return false;
+  }
+
+  // Attempt to get a starting tick count.
+  QueryPerformanceCounter(&liEnd);
+
+  // Get the difference...  NB: This is in seconds....
+  QueryPerformanceFrequency(&liCountsPerSecond);
+  dDifference = (((double)liEnd.QuadPart - (double)liStart.QuadPart) /
+                 (double)liCountsPerSecond.QuadPart);
+
+  // Calculate the clock speed.
+  if (this->ChipID.Family == 3) {
+    // 80386 processors....  Loop time is 115 cycles!
+    dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000);
+  } else if (this->ChipID.Family == 4) {
+    // 80486 processors....  Loop time is 47 cycles!
+    dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000);
+  } else if (this->ChipID.Family == 5) {
+    // Pentium processors....  Loop time is 43 cycles!
+    dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000);
+  }
+
+  // Save the clock speed.
+  this->Features.CPUSpeed = (int)dFrequency;
+
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(
+  int CPULevelToCheck)
+{
+  int cpuinfo[4] = { 0, 0, 0, 0 };
+
+  // The extended CPUID is supported by various vendors starting with the
+  // following CPU models:
+  //
+  //    Manufacturer & Chip Name      |    Family     Model    Revision
+  //
+  //    AMD K6, K6-2                  |       5       6      x
+  //    Cyrix GXm, Cyrix III "Joshua" |       5       4      x
+  //    IDT C6-2                      |       5       8      x
+  //    VIA Cyrix III                 |       6       5      x
+  //    Transmeta Crusoe              |       5       x      x
+  //    Intel Pentium 4               |       f       x      x
+  //
+
+  // We check to see if a supported processor is present...
+  if (this->ChipManufacturer == AMD) {
+    if (this->ChipID.Family < 5)
+      return false;
+    if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6))
+      return false;
+  } else if (this->ChipManufacturer == Cyrix) {
+    if (this->ChipID.Family < 5)
+      return false;
+    if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4))
+      return false;
+    if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5))
+      return false;
+  } else if (this->ChipManufacturer == IDT) {
+    if (this->ChipID.Family < 5)
+      return false;
+    if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8))
+      return false;
+  } else if (this->ChipManufacturer == Transmeta) {
+    if (this->ChipID.Family < 5)
+      return false;
+  } else if (this->ChipManufacturer == Intel) {
+    if (this->ChipID.Family < 0xf) {
+      return false;
+    }
+  }
+
+#if USE_CPUID
+  if (!call_cpuid(0x80000000, cpuinfo)) {
+    return false;
+  }
+#endif
+
+  // Now we have to check the level wanted vs level returned...
+  int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF);
+  int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF);
+
+  // Check to see if the level provided is supported...
+  if (nLevelWanted > nLevelReturn) {
+    return false;
+  }
+
+  return true;
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
+{
+
+  // Check that we are not using an Intel processor as it does not support
+  // this.
+  if (this->ChipManufacturer == Intel) {
+    return false;
+  }
+
+  // Check to see if what we are about to do is supported...
+  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000001))) {
+    return false;
+  }
+
+#if USE_CPUID
+  int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 };
+
+  if (!call_cpuid(0x80000001, localCPUExtendedFeatures)) {
+    return false;
+  }
+
+  // Retrieve the extended features of CPU present.
+  this->Features.ExtendedFeatures.Has3DNow =
+    ((localCPUExtendedFeatures[3] & 0x80000000) !=
+     0); // 3DNow Present --> Bit 31.
+  this->Features.ExtendedFeatures.Has3DNowPlus =
+    ((localCPUExtendedFeatures[3] & 0x40000000) !=
+     0); // 3DNow+ Present -- > Bit 30.
+  this->Features.ExtendedFeatures.HasSSEMMX =
+    ((localCPUExtendedFeatures[3] & 0x00400000) !=
+     0); // SSE MMX Present --> Bit 22.
+  this->Features.ExtendedFeatures.SupportsMP =
+    ((localCPUExtendedFeatures[3] & 0x00080000) !=
+     0); // MP Capable -- > Bit 19.
+
+  // Retrieve AMD specific extended features.
+  if (this->ChipManufacturer == AMD) {
+    this->Features.ExtendedFeatures.HasMMXPlus =
+      ((localCPUExtendedFeatures[3] & 0x00400000) !=
+       0); // AMD specific: MMX-SSE --> Bit 22
+  }
+
+  // Retrieve Cyrix specific extended features.
+  if (this->ChipManufacturer == Cyrix) {
+    this->Features.ExtendedFeatures.HasMMXPlus =
+      ((localCPUExtendedFeatures[3] & 0x01000000) !=
+       0); // Cyrix specific: Extended MMX --> Bit 24
+  }
+
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
+{
+  // Check to see if the processor supports the processor serial number.
+  if (!this->Features.HasSerial) {
+    return false;
+  }
+
+#if USE_CPUID
+  int SerialNumber[4];
+
+  if (!call_cpuid(3, SerialNumber)) {
+    return false;
+  }
+
+  // Process the returned information.
+  //    ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB:
+  //    Transmeta only ?!?
+  //    ;        ecx: middle 32 bits are the processor signature bits
+  //    ;        edx: bottom 32 bits are the processor signature bits
+  char sn[128];
+  sprintf(sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x",
+          ((SerialNumber[1] & 0xff000000) >> 24),
+          ((SerialNumber[1] & 0x00ff0000) >> 16),
+          ((SerialNumber[1] & 0x0000ff00) >> 8),
+          ((SerialNumber[1] & 0x000000ff) >> 0),
+          ((SerialNumber[2] & 0xff000000) >> 24),
+          ((SerialNumber[2] & 0x00ff0000) >> 16),
+          ((SerialNumber[2] & 0x0000ff00) >> 8),
+          ((SerialNumber[2] & 0x000000ff) >> 0),
+          ((SerialNumber[3] & 0xff000000) >> 24),
+          ((SerialNumber[3] & 0x00ff0000) >> 16),
+          ((SerialNumber[3] & 0x0000ff00) >> 8),
+          ((SerialNumber[3] & 0x000000ff) >> 0));
+  this->ChipID.SerialNumber = sn;
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveCPUPowerManagement()
+{
+  // Check to see if what we are about to do is supported...
+  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000007))) {
+    this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false;
+    this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false;
+    this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false;
+    return false;
+  }
+
+#if USE_CPUID
+  int localCPUPowerManagement[4] = { 0, 0, 0, 0 };
+
+  if (!call_cpuid(0x80000007, localCPUPowerManagement)) {
+    return false;
+  }
+
+  // Check for the power management capabilities of the CPU.
+  this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode =
+    ((localCPUPowerManagement[3] & 0x00000001) != 0);
+  this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID =
+    ((localCPUPowerManagement[3] & 0x00000002) != 0);
+  this->Features.ExtendedFeatures.PowerManagement.HasVoltageID =
+    ((localCPUPowerManagement[3] & 0x00000004) != 0);
+
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+#if USE_CPUID
+// Used only in USE_CPUID implementation below.
+static void SystemInformationStripLeadingSpace(std::string& str)
+{
+  // Because some manufacturers have leading white space - we have to
+  // post-process the name.
+  std::string::size_type pos = str.find_first_not_of(" ");
+  if (pos != std::string::npos) {
+    str = str.substr(pos);
+  }
+}
+#endif
+
+/** */
+bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()
+{
+  // Check to see if what we are about to do is supported...
+  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000002)))
+    return false;
+  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000003)))
+    return false;
+  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000004)))
+    return false;
+
+#if USE_CPUID
+  int CPUExtendedIdentity[12];
+
+  if (!call_cpuid(0x80000002, CPUExtendedIdentity)) {
+    return false;
+  }
+  if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4)) {
+    return false;
+  }
+  if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8)) {
+    return false;
+  }
+
+  // Process the returned information.
+  char nbuf[49];
+  memcpy(&(nbuf[0]), &(CPUExtendedIdentity[0]), sizeof(int));
+  memcpy(&(nbuf[4]), &(CPUExtendedIdentity[1]), sizeof(int));
+  memcpy(&(nbuf[8]), &(CPUExtendedIdentity[2]), sizeof(int));
+  memcpy(&(nbuf[12]), &(CPUExtendedIdentity[3]), sizeof(int));
+  memcpy(&(nbuf[16]), &(CPUExtendedIdentity[4]), sizeof(int));
+  memcpy(&(nbuf[20]), &(CPUExtendedIdentity[5]), sizeof(int));
+  memcpy(&(nbuf[24]), &(CPUExtendedIdentity[6]), sizeof(int));
+  memcpy(&(nbuf[28]), &(CPUExtendedIdentity[7]), sizeof(int));
+  memcpy(&(nbuf[32]), &(CPUExtendedIdentity[8]), sizeof(int));
+  memcpy(&(nbuf[36]), &(CPUExtendedIdentity[9]), sizeof(int));
+  memcpy(&(nbuf[40]), &(CPUExtendedIdentity[10]), sizeof(int));
+  memcpy(&(nbuf[44]), &(CPUExtendedIdentity[11]), sizeof(int));
+  nbuf[48] = '\0';
+  this->ChipID.ProcessorName = nbuf;
+  this->ChipID.ModelName = nbuf;
+
+  // Because some manufacturers have leading white space - we have to
+  // post-process the name.
+  SystemInformationStripLeadingSpace(this->ChipID.ProcessorName);
+  return true;
+#else
+  return false;
+#endif
+}
+
+/** */
+bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
+{
+  // Start by decided which manufacturer we are using....
+  switch (this->ChipManufacturer) {
+    case Intel:
+      // Check the family / model / revision to determine the CPU ID.
+      switch (this->ChipID.Family) {
+        case 3:
+          this->ChipID.ProcessorName = "Newer i80386 family";
+          break;
+        case 4:
+          switch (this->ChipID.Model) {
+            case 0:
+              this->ChipID.ProcessorName = "i80486DX-25/33";
+              break;
+            case 1:
+              this->ChipID.ProcessorName = "i80486DX-50";
+              break;
+            case 2:
+              this->ChipID.ProcessorName = "i80486SX";
+              break;
+            case 3:
+              this->ChipID.ProcessorName = "i80486DX2";
+              break;
+            case 4:
+              this->ChipID.ProcessorName = "i80486SL";
+              break;
+            case 5:
+              this->ChipID.ProcessorName = "i80486SX2";
+              break;
+            case 7:
+              this->ChipID.ProcessorName = "i80486DX2 WriteBack";
+              break;
+            case 8:
+              this->ChipID.ProcessorName = "i80486DX4";
+              break;
+            case 9:
+              this->ChipID.ProcessorName = "i80486DX4 WriteBack";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown 80486 family";
+              return false;
+          }
+          break;
+        case 5:
+          switch (this->ChipID.Model) {
+            case 0:
+              this->ChipID.ProcessorName = "P5 A-Step";
+              break;
+            case 1:
+              this->ChipID.ProcessorName = "P5";
+              break;
+            case 2:
+              this->ChipID.ProcessorName = "P54C";
+              break;
+            case 3:
+              this->ChipID.ProcessorName = "P24T OverDrive";
+              break;
+            case 4:
+              this->ChipID.ProcessorName = "P55C";
+              break;
+            case 7:
+              this->ChipID.ProcessorName = "P54C";
+              break;
+            case 8:
+              this->ChipID.ProcessorName = "P55C (0.25micron)";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown Pentium family";
+              return false;
+          }
+          break;
+        case 6:
+          switch (this->ChipID.Model) {
+            case 0:
+              this->ChipID.ProcessorName = "P6 A-Step";
+              break;
+            case 1:
+              this->ChipID.ProcessorName = "P6";
+              break;
+            case 3:
+              this->ChipID.ProcessorName = "Pentium II (0.28 micron)";
+              break;
+            case 5:
+              this->ChipID.ProcessorName = "Pentium II (0.25 micron)";
+              break;
+            case 6:
+              this->ChipID.ProcessorName = "Pentium II With On-Die L2 Cache";
+              break;
+            case 7:
+              this->ChipID.ProcessorName = "Pentium III (0.25 micron)";
+              break;
+            case 8:
+              this->ChipID.ProcessorName =
+                "Pentium III (0.18 micron) With 256 KB On-Die L2 Cache ";
+              break;
+            case 0xa:
+              this->ChipID.ProcessorName =
+                "Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache ";
+              break;
+            case 0xb:
+              this->ChipID.ProcessorName = "Pentium III (0.13 micron) With "
+                                           "256 Or 512 KB On-Die L2 Cache ";
+              break;
+            case 23:
+              this->ChipID.ProcessorName =
+                "Intel(R) Core(TM)2 Duo CPU     T9500  @ 2.60GHz";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown P6 family";
+              return false;
+          }
+          break;
+        case 7:
+          this->ChipID.ProcessorName = "Intel Merced (IA-64)";
+          break;
+        case 0xf:
+          // Check the extended family bits...
+          switch (this->ChipID.ExtendedFamily) {
+            case 0:
+              switch (this->ChipID.Model) {
+                case 0:
+                  this->ChipID.ProcessorName = "Pentium IV (0.18 micron)";
+                  break;
+                case 1:
+                  this->ChipID.ProcessorName = "Pentium IV (0.18 micron)";
+                  break;
+                case 2:
+                  this->ChipID.ProcessorName = "Pentium IV (0.13 micron)";
+                  break;
+                default:
+                  this->ChipID.ProcessorName = "Unknown Pentium 4 family";
+                  return false;
+              }
+              break;
+            case 1:
+              this->ChipID.ProcessorName = "Intel McKinley (IA-64)";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Pentium";
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown Intel family";
+          return false;
+      }
+      break;
+
+    case AMD:
+      // Check the family / model / revision to determine the CPU ID.
+      switch (this->ChipID.Family) {
+        case 4:
+          switch (this->ChipID.Model) {
+            case 3:
+              this->ChipID.ProcessorName = "80486DX2";
+              break;
+            case 7:
+              this->ChipID.ProcessorName = "80486DX2 WriteBack";
+              break;
+            case 8:
+              this->ChipID.ProcessorName = "80486DX4";
+              break;
+            case 9:
+              this->ChipID.ProcessorName = "80486DX4 WriteBack";
+              break;
+            case 0xe:
+              this->ChipID.ProcessorName = "5x86";
+              break;
+            case 0xf:
+              this->ChipID.ProcessorName = "5x86WB";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown 80486 family";
+              return false;
+          }
+          break;
+        case 5:
+          switch (this->ChipID.Model) {
+            case 0:
+              this->ChipID.ProcessorName = "SSA5 (PR75, PR90 =  PR100)";
+              break;
+            case 1:
+              this->ChipID.ProcessorName = "5k86 (PR120 =  PR133)";
+              break;
+            case 2:
+              this->ChipID.ProcessorName = "5k86 (PR166)";
+              break;
+            case 3:
+              this->ChipID.ProcessorName = "5k86 (PR200)";
+              break;
+            case 6:
+              this->ChipID.ProcessorName = "K6 (0.30 micron)";
+              break;
+            case 7:
+              this->ChipID.ProcessorName = "K6 (0.25 micron)";
+              break;
+            case 8:
+              this->ChipID.ProcessorName = "K6-2";
+              break;
+            case 9:
+              this->ChipID.ProcessorName = "K6-III";
+              break;
+            case 0xd:
+              this->ChipID.ProcessorName = "K6-2+ or K6-III+ (0.18 micron)";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown 80586 family";
+              return false;
+          }
+          break;
+        case 6:
+          switch (this->ChipID.Model) {
+            case 1:
+              this->ChipID.ProcessorName = "Athlon- (0.25 micron)";
+              break;
+            case 2:
+              this->ChipID.ProcessorName = "Athlon- (0.18 micron)";
+              break;
+            case 3:
+              this->ChipID.ProcessorName = "Duron- (SF core)";
+              break;
+            case 4:
+              this->ChipID.ProcessorName = "Athlon- (Thunderbird core)";
+              break;
+            case 6:
+              this->ChipID.ProcessorName = "Athlon- (Palomino core)";
+              break;
+            case 7:
+              this->ChipID.ProcessorName = "Duron- (Morgan core)";
+              break;
+            case 8:
+              if (this->Features.ExtendedFeatures.SupportsMP)
+                this->ChipID.ProcessorName = "Athlon - MP (Thoroughbred core)";
+              else
+                this->ChipID.ProcessorName = "Athlon - XP (Thoroughbred core)";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown K7 family";
+              return false;
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown AMD family";
+          return false;
+      }
+      break;
+
+    case Transmeta:
+      switch (this->ChipID.Family) {
+        case 5:
+          switch (this->ChipID.Model) {
+            case 4:
+              this->ChipID.ProcessorName = "Crusoe TM3x00 and TM5x00";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown Crusoe family";
+              return false;
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown Transmeta family";
+          return false;
+      }
+      break;
+
+    case Rise:
+      switch (this->ChipID.Family) {
+        case 5:
+          switch (this->ChipID.Model) {
+            case 0:
+              this->ChipID.ProcessorName = "mP6 (0.25 micron)";
+              break;
+            case 2:
+              this->ChipID.ProcessorName = "mP6 (0.18 micron)";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown Rise family";
+              return false;
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown Rise family";
+          return false;
+      }
+      break;
+
+    case UMC:
+      switch (this->ChipID.Family) {
+        case 4:
+          switch (this->ChipID.Model) {
+            case 1:
+              this->ChipID.ProcessorName = "U5D";
+              break;
+            case 2:
+              this->ChipID.ProcessorName = "U5S";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown UMC family";
+              return false;
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown UMC family";
+          return false;
+      }
+      break;
+
+    case IDT:
+      switch (this->ChipID.Family) {
+        case 5:
+          switch (this->ChipID.Model) {
+            case 4:
+              this->ChipID.ProcessorName = "C6";
+              break;
+            case 8:
+              this->ChipID.ProcessorName = "C2";
+              break;
+            case 9:
+              this->ChipID.ProcessorName = "C3";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown IDT\\Centaur family";
+              return false;
+          }
+          break;
+        case 6:
+          switch (this->ChipID.Model) {
+            case 6:
+              this->ChipID.ProcessorName = "VIA Cyrix III - Samuel";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown IDT\\Centaur family";
+              return false;
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown IDT\\Centaur family";
+          return false;
+      }
+      break;
+
+    case Cyrix:
+      switch (this->ChipID.Family) {
+        case 4:
+          switch (this->ChipID.Model) {
+            case 4:
+              this->ChipID.ProcessorName = "MediaGX GX =  GXm";
+              break;
+            case 9:
+              this->ChipID.ProcessorName = "5x86";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown Cx5x86 family";
+              return false;
+          }
+          break;
+        case 5:
+          switch (this->ChipID.Model) {
+            case 2:
+              this->ChipID.ProcessorName = "Cx6x86";
+              break;
+            case 4:
+              this->ChipID.ProcessorName = "MediaGX GXm";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown Cx6x86 family";
+              return false;
+          }
+          break;
+        case 6:
+          switch (this->ChipID.Model) {
+            case 0:
+              this->ChipID.ProcessorName = "6x86MX";
+              break;
+            case 5:
+              this->ChipID.ProcessorName = "Cyrix M2 Core";
+              break;
+            case 6:
+              this->ChipID.ProcessorName = "WinChip C5A Core";
+              break;
+            case 7:
+              this->ChipID.ProcessorName = "WinChip C5B\\C5C Core";
+              break;
+            case 8:
+              this->ChipID.ProcessorName = "WinChip C5C-T Core";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown 6x86MX\\Cyrix III family";
+              return false;
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown Cyrix family";
+          return false;
+      }
+      break;
+
+    case NexGen:
+      switch (this->ChipID.Family) {
+        case 5:
+          switch (this->ChipID.Model) {
+            case 0:
+              this->ChipID.ProcessorName = "Nx586 or Nx586FPU";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown NexGen family";
+              return false;
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown NexGen family";
+          return false;
+      }
+      break;
+
+    case NSC:
+      this->ChipID.ProcessorName = "Cx486SLC \\ DLC \\ Cx486S A-Step";
+      break;
+
+    case Sun:
+    case IBM:
+    case Motorola:
+    case HP:
+    case UnknownManufacturer:
+    default:
+      this->ChipID.ProcessorName =
+        "Unknown family"; // We cannot identify the processor.
+      return false;
+  }
+
+  return true;
+}
+
+/** Extract a value from the CPUInfo file */
+std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(
+  std::string buffer, const char* word, size_t init)
+{
+  size_t pos = buffer.find(word, init);
+  if (pos != buffer.npos) {
+    this->CurrentPositionInFile = pos;
+    pos = buffer.find(":", pos);
+    size_t pos2 = buffer.find("\n", pos);
+    if (pos != buffer.npos && pos2 != buffer.npos) {
+      // It may happen that the beginning matches, but this is still not the
+      // requested key.
+      // An example is looking for "cpu" when "cpu family" comes first. So we
+      // check that
+      // we have only spaces from here to pos, otherwise we search again.
+      for (size_t i = this->CurrentPositionInFile + strlen(word); i < pos;
+           ++i) {
+        if (buffer[i] != ' ' && buffer[i] != '\t') {
+          return this->ExtractValueFromCpuInfoFile(buffer, word, pos2);
+        }
+      }
+      return buffer.substr(pos + 2, pos2 - pos - 2);
+    }
+  }
+  this->CurrentPositionInFile = buffer.npos;
+  return "";
+}
+
+/** Query for the cpu status */
+bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile()
+{
+  this->NumberOfLogicalCPU = 0;
+  this->NumberOfPhysicalCPU = 0;
+  std::string buffer;
+
+  FILE* fd = fopen("/proc/cpuinfo", "r");
+  if (!fd) {
+    std::cout << "Problem opening /proc/cpuinfo" << std::endl;
+    return false;
+  }
+
+  size_t fileSize = 0;
+  while (!feof(fd)) {
+    buffer += static_cast<char>(fgetc(fd));
+    fileSize++;
+  }
+  fclose(fd);
+  buffer.resize(fileSize - 2);
+  // Number of logical CPUs (combination of multiple processors, multi-core
+  // and SMT)
+  size_t pos = buffer.find("processor\t");
+  while (pos != buffer.npos) {
+    this->NumberOfLogicalCPU++;
+    pos = buffer.find("processor\t", pos + 1);
+  }
+
+#ifdef __linux
+  // Count sockets.
+  std::set<int> PhysicalIDs;
+  std::string idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id");
+  while (this->CurrentPositionInFile != buffer.npos) {
+    int id = atoi(idc.c_str());
+    PhysicalIDs.insert(id);
+    idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id",
+                                            this->CurrentPositionInFile + 1);
+  }
+  uint64_t NumberOfSockets = PhysicalIDs.size();
+  NumberOfSockets = std::max(NumberOfSockets, (uint64_t)1);
+  // Physical ids returned by Linux don't distinguish cores.
+  // We want to record the total number of cores in this->NumberOfPhysicalCPU
+  // (checking only the first proc)
+  std::string Cores = this->ExtractValueFromCpuInfoFile(buffer, "cpu cores");
+  unsigned int NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str());
+  NumberOfCoresPerSocket = std::max(NumberOfCoresPerSocket, 1u);
+  this->NumberOfPhysicalCPU =
+    NumberOfCoresPerSocket * (unsigned int)NumberOfSockets;
+
+#else // __CYGWIN__
+  // does not have "physical id" entries, neither "cpu cores"
+  // this has to be fixed for hyper-threading.
+  std::string cpucount =
+    this->ExtractValueFromCpuInfoFile(buffer, "cpu count");
+  this->NumberOfPhysicalCPU = this->NumberOfLogicalCPU =
+    atoi(cpucount.c_str());
+#endif
+  // gotta have one, and if this is 0 then we get a / by 0n
+  // better to have a bad answer than a crash
+  if (this->NumberOfPhysicalCPU <= 0) {
+    this->NumberOfPhysicalCPU = 1;
+  }
+  // LogicalProcessorsPerPhysical>1 => SMT.
+  this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical =
+    this->NumberOfLogicalCPU / this->NumberOfPhysicalCPU;
+
+  // CPU speed (checking only the first processor)
+  std::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "cpu MHz");
+  if (!CPUSpeed.empty()) {
+    this->CPUSpeedInMHz = static_cast<float>(atof(CPUSpeed.c_str()));
+  }
+#ifdef __linux
+  else {
+    // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal
+    CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "Cpu0ClkTck");
+    this->CPUSpeedInMHz =
+      static_cast<float>(strtoull(CPUSpeed.c_str(), 0, 16)) / 1000000.0f;
+  }
+#endif
+
+  // Chip family
+  std::string familyStr =
+    this->ExtractValueFromCpuInfoFile(buffer, "cpu family");
+  if (familyStr.empty()) {
+    familyStr = this->ExtractValueFromCpuInfoFile(buffer, "CPU architecture");
+  }
+  this->ChipID.Family = atoi(familyStr.c_str());
+
+  // Chip Vendor
+  this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer, "vendor_id");
+  this->FindManufacturer(familyStr);
+
+  // second try for setting family
+  if (this->ChipID.Family == 0 && this->ChipManufacturer == HP) {
+    if (familyStr == "PA-RISC 1.1a")
+      this->ChipID.Family = 0x11a;
+    else if (familyStr == "PA-RISC 2.0")
+      this->ChipID.Family = 0x200;
+    // If you really get CMake to work on a machine not belonging to
+    // any of those families I owe you a dinner if you get it to
+    // contribute nightly builds regularly.
+  }
+
+  // Chip Model
+  this->ChipID.Model =
+    atoi(this->ExtractValueFromCpuInfoFile(buffer, "model").c_str());
+  if (!this->RetrieveClassicalCPUIdentity()) {
+    // Some platforms (e.g. PA-RISC) tell us their CPU name here.
+    // Note: x86 does not.
+    std::string cpuname = this->ExtractValueFromCpuInfoFile(buffer, "cpu");
+    if (!cpuname.empty()) {
+      this->ChipID.ProcessorName = cpuname;
+    }
+  }
+
+  // Chip revision
+  std::string cpurev = this->ExtractValueFromCpuInfoFile(buffer, "stepping");
+  if (cpurev.empty()) {
+    cpurev = this->ExtractValueFromCpuInfoFile(buffer, "CPU revision");
+  }
+  this->ChipID.Revision = atoi(cpurev.c_str());
+
+  // Chip Model Name
+  this->ChipID.ModelName =
+    this->ExtractValueFromCpuInfoFile(buffer, "model name").c_str();
+
+  // L1 Cache size
+  // Different architectures may show different names for the caches.
+  // Sum up everything we find.
+  std::vector<const char*> cachename;
+  cachename.clear();
+
+  cachename.push_back("cache size"); // e.g. x86
+  cachename.push_back("I-cache");    // e.g. PA-RISC
+  cachename.push_back("D-cache");    // e.g. PA-RISC
+
+  this->Features.L1CacheSize = 0;
+  for (size_t index = 0; index < cachename.size(); index++) {
+    std::string cacheSize =
+      this->ExtractValueFromCpuInfoFile(buffer, cachename[index]);
+    if (!cacheSize.empty()) {
+      pos = cacheSize.find(" KB");
+      if (pos != cacheSize.npos) {
+        cacheSize = cacheSize.substr(0, pos);
+      }
+      this->Features.L1CacheSize += atoi(cacheSize.c_str());
+    }
+  }
+
+  // processor feature flags (probably x86 specific)
+  std::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer, "flags");
+  if (!cpurev.empty()) {
+    // now we can match every flags as space + flag + space
+    cpuflags = " " + cpuflags + " ";
+    if ((cpuflags.find(" fpu ") != std::string::npos)) {
+      this->Features.HasFPU = true;
+    }
+    if ((cpuflags.find(" tsc ") != std::string::npos)) {
+      this->Features.HasTSC = true;
+    }
+    if ((cpuflags.find(" mmx ") != std::string::npos)) {
+      this->Features.HasMMX = true;
+    }
+    if ((cpuflags.find(" sse ") != std::string::npos)) {
+      this->Features.HasSSE = true;
+    }
+    if ((cpuflags.find(" sse2 ") != std::string::npos)) {
+      this->Features.HasSSE2 = true;
+    }
+    if ((cpuflags.find(" apic ") != std::string::npos)) {
+      this->Features.HasAPIC = true;
+    }
+    if ((cpuflags.find(" cmov ") != std::string::npos)) {
+      this->Features.HasCMOV = true;
+    }
+    if ((cpuflags.find(" mtrr ") != std::string::npos)) {
+      this->Features.HasMTRR = true;
+    }
+    if ((cpuflags.find(" acpi ") != std::string::npos)) {
+      this->Features.HasACPI = true;
+    }
+    if ((cpuflags.find(" 3dnow ") != std::string::npos)) {
+      this->Features.ExtendedFeatures.Has3DNow = true;
+    }
+  }
+
+  return true;
+}
+
+bool SystemInformationImplementation::QueryProcessorBySysconf()
+{
+#if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN)
+// IRIX names this slightly different
+#define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
+#endif
+
+#ifdef _SC_NPROCESSORS_ONLN
+  long c = sysconf(_SC_NPROCESSORS_ONLN);
+  if (c <= 0) {
+    return false;
+  }
+
+  this->NumberOfPhysicalCPU = static_cast<unsigned int>(c);
+  this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryProcessor()
+{
+  return this->QueryProcessorBySysconf();
+}
+
+/**
+Get total system RAM in units of KiB.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetHostMemoryTotal()
+{
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER < 1300
+  MEMORYSTATUS stat;
+  stat.dwLength = sizeof(stat);
+  GlobalMemoryStatus(&stat);
+  return stat.dwTotalPhys / 1024;
+#else
+  MEMORYSTATUSEX statex;
+  statex.dwLength = sizeof(statex);
+  GlobalMemoryStatusEx(&statex);
+  return statex.ullTotalPhys / 1024;
+#endif
+#elif defined(__linux)
+  SystemInformation::LongLong memTotal = 0;
+  int ierr = GetFieldFromFile("/proc/meminfo", "MemTotal:", memTotal);
+  if (ierr) {
+    return -1;
+  }
+  return memTotal;
+#elif defined(__APPLE__)
+  uint64_t mem;
+  size_t len = sizeof(mem);
+  int ierr = sysctlbyname("hw.memsize", &mem, &len, NULL, 0);
+  if (ierr) {
+    return -1;
+  }
+  return mem / 1024;
+#else
+  return 0;
+#endif
+}
+
+/**
+Get total system RAM in units of KiB. This may differ from the
+host total if a host-wide resource limit is applied.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetHostMemoryAvailable(
+  const char* hostLimitEnvVarName)
+{
+  SystemInformation::LongLong memTotal = this->GetHostMemoryTotal();
+
+  // the following mechanism is provided for systems that
+  // apply resource limits across groups of processes.
+  // this is of use on certain SMP systems (eg. SGI UV)
+  // where the host has a large amount of ram but a given user's
+  // access to it is severly restricted. The system will
+  // apply a limit across a set of processes. Units are in KiB.
+  if (hostLimitEnvVarName) {
+    const char* hostLimitEnvVarValue = getenv(hostLimitEnvVarName);
+    if (hostLimitEnvVarValue) {
+      SystemInformation::LongLong hostLimit =
+        atoLongLong(hostLimitEnvVarValue);
+      if (hostLimit > 0) {
+        memTotal = min(hostLimit, memTotal);
+      }
+    }
+  }
+
+  return memTotal;
+}
+
+/**
+Get total system RAM in units of KiB. This may differ from the
+host total if a per-process resource limit is applied.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetProcMemoryAvailable(
+  const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
+{
+  SystemInformation::LongLong memAvail =
+    this->GetHostMemoryAvailable(hostLimitEnvVarName);
+
+  // the following mechanism is provide for systems where rlimits
+  // are not employed. Units are in KiB.
+  if (procLimitEnvVarName) {
+    const char* procLimitEnvVarValue = getenv(procLimitEnvVarName);
+    if (procLimitEnvVarValue) {
+      SystemInformation::LongLong procLimit =
+        atoLongLong(procLimitEnvVarValue);
+      if (procLimit > 0) {
+        memAvail = min(procLimit, memAvail);
+      }
+    }
+  }
+
+#if defined(__linux)
+  int ierr;
+  ResourceLimitType rlim;
+  ierr = GetResourceLimit(RLIMIT_DATA, &rlim);
+  if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) {
+    memAvail =
+      min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail);
+  }
+
+  ierr = GetResourceLimit(RLIMIT_AS, &rlim);
+  if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) {
+    memAvail =
+      min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail);
+  }
+#elif defined(__APPLE__)
+  struct rlimit rlim;
+  int ierr;
+  ierr = getrlimit(RLIMIT_DATA, &rlim);
+  if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) {
+    memAvail =
+      min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail);
+  }
+
+  ierr = getrlimit(RLIMIT_RSS, &rlim);
+  if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) {
+    memAvail =
+      min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail);
+  }
+#endif
+
+  return memAvail;
+}
+
+/**
+Get RAM used by all processes in the host, in units of KiB.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetHostMemoryUsed()
+{
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER < 1300
+  MEMORYSTATUS stat;
+  stat.dwLength = sizeof(stat);
+  GlobalMemoryStatus(&stat);
+  return (stat.dwTotalPhys - stat.dwAvailPhys) / 1024;
+#else
+  MEMORYSTATUSEX statex;
+  statex.dwLength = sizeof(statex);
+  GlobalMemoryStatusEx(&statex);
+  return (statex.ullTotalPhys - statex.ullAvailPhys) / 1024;
+#endif
+#elif defined(__linux)
+  // First try to use MemAvailable, but it only works on newer kernels
+  const char* names2[3] = { "MemTotal:", "MemAvailable:", NULL };
+  SystemInformation::LongLong values2[2] = { SystemInformation::LongLong(0) };
+  int ierr = GetFieldsFromFile("/proc/meminfo", names2, values2);
+  if (ierr) {
+    const char* names4[5] = { "MemTotal:", "MemFree:", "Buffers:", "Cached:",
+                              NULL };
+    SystemInformation::LongLong values4[4] = { SystemInformation::LongLong(
+      0) };
+    ierr = GetFieldsFromFile("/proc/meminfo", names4, values4);
+    if (ierr) {
+      return ierr;
+    }
+    SystemInformation::LongLong& memTotal = values4[0];
+    SystemInformation::LongLong& memFree = values4[1];
+    SystemInformation::LongLong& memBuffers = values4[2];
+    SystemInformation::LongLong& memCached = values4[3];
+    return memTotal - memFree - memBuffers - memCached;
+  }
+  SystemInformation::LongLong& memTotal = values2[0];
+  SystemInformation::LongLong& memAvail = values2[1];
+  return memTotal - memAvail;
+#elif defined(__APPLE__)
+  SystemInformation::LongLong psz = getpagesize();
+  if (psz < 1) {
+    return -1;
+  }
+  const char* names[3] = { "Pages wired down:", "Pages active:", NULL };
+  SystemInformation::LongLong values[2] = { SystemInformation::LongLong(0) };
+  int ierr = GetFieldsFromCommand("vm_stat", names, values);
+  if (ierr) {
+    return -1;
+  }
+  SystemInformation::LongLong& vmWired = values[0];
+  SystemInformation::LongLong& vmActive = values[1];
+  return ((vmActive + vmWired) * psz) / 1024;
+#else
+  return 0;
+#endif
+}
+
+/**
+Get system RAM used by the process associated with the given
+process id in units of KiB.
+*/
+SystemInformation::LongLong
+SystemInformationImplementation::GetProcMemoryUsed()
+{
+#if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI)
+  long pid = GetCurrentProcessId();
+  HANDLE hProc;
+  hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid);
+  if (hProc == 0) {
+    return -1;
+  }
+  PROCESS_MEMORY_COUNTERS pmc;
+  int ok = GetProcessMemoryInfo(hProc, &pmc, sizeof(pmc));
+  CloseHandle(hProc);
+  if (!ok) {
+    return -2;
+  }
+  return pmc.WorkingSetSize / 1024;
+#elif defined(__linux)
+  SystemInformation::LongLong memUsed = 0;
+  int ierr = GetFieldFromFile("/proc/self/status", "VmRSS:", memUsed);
+  if (ierr) {
+    return -1;
+  }
+  return memUsed;
+#elif defined(__APPLE__)
+  SystemInformation::LongLong memUsed = 0;
+  pid_t pid = getpid();
+  std::ostringstream oss;
+  oss << "ps -o rss= -p " << pid;
+  FILE* file = popen(oss.str().c_str(), "r");
+  if (file == 0) {
+    return -1;
+  }
+  oss.str("");
+  while (!feof(file) && !ferror(file)) {
+    char buf[256] = { '\0' };
+    errno = 0;
+    size_t nRead = fread(buf, 1, 256, file);
+    if (ferror(file) && (errno == EINTR)) {
+      clearerr(file);
+    }
+    if (nRead)
+      oss << buf;
+  }
+  int ierr = ferror(file);
+  pclose(file);
+  if (ierr) {
+    return -2;
+  }
+  std::istringstream iss(oss.str());
+  iss >> memUsed;
+  return memUsed;
+#else
+  return 0;
+#endif
+}
+
+double SystemInformationImplementation::GetLoadAverage()
+{
+#if defined(KWSYS_CXX_HAS_GETLOADAVG)
+  double loadavg[3] = { 0.0, 0.0, 0.0 };
+  if (getloadavg(loadavg, 3) > 0) {
+    return loadavg[0];
+  }
+  return -0.0;
+#elif defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes)
+  // Old windows.h headers do not provide GetSystemTimes.
+  typedef BOOL(WINAPI * GetSystemTimesType)(LPFILETIME, LPFILETIME,
+                                            LPFILETIME);
+  static GetSystemTimesType pGetSystemTimes =
+    (GetSystemTimesType)GetProcAddress(GetModuleHandleW(L"kernel32"),
+                                       "GetSystemTimes");
+  FILETIME idleTime, kernelTime, userTime;
+  if (pGetSystemTimes && pGetSystemTimes(&idleTime, &kernelTime, &userTime)) {
+    unsigned __int64 const idleTicks = fileTimeToUInt64(idleTime);
+    unsigned __int64 const totalTicks =
+      fileTimeToUInt64(kernelTime) + fileTimeToUInt64(userTime);
+    return calculateCPULoad(idleTicks, totalTicks) * GetNumberOfPhysicalCPU();
+  }
+  return -0.0;
+#else
+  // Not implemented on this platform.
+  return -0.0;
+#endif
+}
+
+/**
+Get the process id of the running process.
+*/
+SystemInformation::LongLong SystemInformationImplementation::GetProcessId()
+{
+#if defined(_WIN32)
+  return GetCurrentProcessId();
+#elif defined(__linux) || defined(__APPLE__)
+  return getpid();
+#else
+  return -1;
+#endif
+}
+
+/**
+return current program stack in a string
+demangle cxx symbols if possible.
+*/
+std::string SystemInformationImplementation::GetProgramStack(int firstFrame,
+                                                             int wholePath)
+{
+  std::string programStack = ""
+#if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+                             "WARNING: The stack could not be examined "
+                             "because backtrace is not supported.\n"
+#elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD)
+                             "WARNING: The stack trace will not use advanced "
+                             "capabilities because this is a release build.\n"
+#else
+#if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+                             "WARNING: Function names will not be demangled "
+                             "because "
+                             "dladdr is not available.\n"
+#endif
+#if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
+                             "WARNING: Function names will not be demangled "
+                             "because cxxabi is not available.\n"
+#endif
+#endif
+    ;
+
+  std::ostringstream oss;
+#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+  void* stackSymbols[256];
+  int nFrames = backtrace(stackSymbols, 256);
+  for (int i = firstFrame; i < nFrames; ++i) {
+    SymbolProperties symProps;
+    symProps.SetReportPath(wholePath);
+    symProps.Initialize(stackSymbols[i]);
+    oss << symProps << std::endl;
+  }
+#else
+  (void)firstFrame;
+  (void)wholePath;
+#endif
+  programStack += oss.str();
+
+  return programStack;
+}
+
+/**
+when set print stack trace in response to common signals.
+*/
+void SystemInformationImplementation::SetStackTraceOnError(int enable)
+{
+#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+  static int saOrigValid = 0;
+  static struct sigaction saABRTOrig;
+  static struct sigaction saSEGVOrig;
+  static struct sigaction saTERMOrig;
+  static struct sigaction saINTOrig;
+  static struct sigaction saILLOrig;
+  static struct sigaction saBUSOrig;
+  static struct sigaction saFPEOrig;
+
+  if (enable && !saOrigValid) {
+    // save the current actions
+    sigaction(SIGABRT, 0, &saABRTOrig);
+    sigaction(SIGSEGV, 0, &saSEGVOrig);
+    sigaction(SIGTERM, 0, &saTERMOrig);
+    sigaction(SIGINT, 0, &saINTOrig);
+    sigaction(SIGILL, 0, &saILLOrig);
+    sigaction(SIGBUS, 0, &saBUSOrig);
+    sigaction(SIGFPE, 0, &saFPEOrig);
+
+    // enable read, disable write
+    saOrigValid = 1;
+
+    // install ours
+    struct sigaction sa;
+    sa.sa_sigaction = (SigAction)StacktraceSignalHandler;
+    sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
+#ifdef SA_RESTART
+    sa.sa_flags |= SA_RESTART;
+#endif
+    sigemptyset(&sa.sa_mask);
+
+    sigaction(SIGABRT, &sa, 0);
+    sigaction(SIGSEGV, &sa, 0);
+    sigaction(SIGTERM, &sa, 0);
+    sigaction(SIGINT, &sa, 0);
+    sigaction(SIGILL, &sa, 0);
+    sigaction(SIGBUS, &sa, 0);
+    sigaction(SIGFPE, &sa, 0);
+  } else if (!enable && saOrigValid) {
+    // restore previous actions
+    sigaction(SIGABRT, &saABRTOrig, 0);
+    sigaction(SIGSEGV, &saSEGVOrig, 0);
+    sigaction(SIGTERM, &saTERMOrig, 0);
+    sigaction(SIGINT, &saINTOrig, 0);
+    sigaction(SIGILL, &saILLOrig, 0);
+    sigaction(SIGBUS, &saBUSOrig, 0);
+    sigaction(SIGFPE, &saFPEOrig, 0);
+
+    // enable write, disable read
+    saOrigValid = 0;
+  }
+#else
+  // avoid warning C4100
+  (void)enable;
+#endif
+}
+
+bool SystemInformationImplementation::QueryWindowsMemory()
+{
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER < 1300
+  MEMORYSTATUS ms;
+  unsigned long tv, tp, av, ap;
+  ms.dwLength = sizeof(ms);
+  GlobalMemoryStatus(&ms);
+#define MEM_VAL(value) dw##value
+#else
+  MEMORYSTATUSEX ms;
+  DWORDLONG tv, tp, av, ap;
+  ms.dwLength = sizeof(ms);
+  if (0 == GlobalMemoryStatusEx(&ms)) {
+    return 0;
+  }
+#define MEM_VAL(value) ull##value
+#endif
+  tv = ms.MEM_VAL(TotalPageFile);
+  tp = ms.MEM_VAL(TotalPhys);
+  av = ms.MEM_VAL(AvailPageFile);
+  ap = ms.MEM_VAL(AvailPhys);
+  this->TotalVirtualMemory = tv >> 10 >> 10;
+  this->TotalPhysicalMemory = tp >> 10 >> 10;
+  this->AvailableVirtualMemory = av >> 10 >> 10;
+  this->AvailablePhysicalMemory = ap >> 10 >> 10;
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryLinuxMemory()
+{
+#if defined(__linux)
+  unsigned long tv = 0;
+  unsigned long tp = 0;
+  unsigned long av = 0;
+  unsigned long ap = 0;
+
+  char buffer[1024]; // for reading lines
+
+  int linuxMajor = 0;
+  int linuxMinor = 0;
+
+  // Find the Linux kernel version first
+  struct utsname unameInfo;
+  int errorFlag = uname(&unameInfo);
+  if (errorFlag != 0) {
+    std::cout << "Problem calling uname(): " << strerror(errno) << std::endl;
+    return false;
+  }
+
+  if (strlen(unameInfo.release) >= 3) {
+    // release looks like "2.6.3-15mdk-i686-up-4GB"
+    char majorChar = unameInfo.release[0];
+    char minorChar = unameInfo.release[2];
+
+    if (isdigit(majorChar)) {
+      linuxMajor = majorChar - '0';
+    }
+
+    if (isdigit(minorChar)) {
+      linuxMinor = minorChar - '0';
+    }
+  }
+
+  FILE* fd = fopen("/proc/meminfo", "r");
+  if (!fd) {
+    std::cout << "Problem opening /proc/meminfo" << std::endl;
+    return false;
+  }
+
+  if (linuxMajor >= 3 || ((linuxMajor >= 2) && (linuxMinor >= 6))) {
+    // new /proc/meminfo format since kernel 2.6.x
+    // Rigorously, this test should check from the developping version 2.5.x
+    // that introduced the new format...
+
+    enum
+    {
+      mMemTotal,
+      mMemFree,
+      mBuffers,
+      mCached,
+      mSwapTotal,
+      mSwapFree
+    };
+    const char* format[6] = { "MemTotal:%lu kB",  "MemFree:%lu kB",
+                              "Buffers:%lu kB",   "Cached:%lu kB",
+                              "SwapTotal:%lu kB", "SwapFree:%lu kB" };
+    bool have[6] = { false, false, false, false, false, false };
+    unsigned long value[6];
+    int count = 0;
+    while (fgets(buffer, static_cast<int>(sizeof(buffer)), fd)) {
+      for (int i = 0; i < 6; ++i) {
+        if (!have[i] && sscanf(buffer, format[i], &value[i]) == 1) {
+          have[i] = true;
+          ++count;
+        }
+      }
+    }
+    if (count == 6) {
+      this->TotalPhysicalMemory = value[mMemTotal] / 1024;
+      this->AvailablePhysicalMemory =
+        (value[mMemFree] + value[mBuffers] + value[mCached]) / 1024;
+      this->TotalVirtualMemory = value[mSwapTotal] / 1024;
+      this->AvailableVirtualMemory = value[mSwapFree] / 1024;
+    } else {
+      std::cout << "Problem parsing /proc/meminfo" << std::endl;
+      fclose(fd);
+      return false;
+    }
+  } else {
+    // /proc/meminfo format for kernel older than 2.6.x
+
+    unsigned long temp;
+    unsigned long cachedMem;
+    unsigned long buffersMem;
+    // Skip "total: used:..."
+    char* r = fgets(buffer, static_cast<int>(sizeof(buffer)), fd);
+    int status = 0;
+    if (r == buffer) {
+      status += fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n", &tp, &temp, &ap,
+                       &temp, &buffersMem, &cachedMem);
+    }
+    if (status == 6) {
+      status += fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av);
+    }
+    if (status == 9) {
+      this->TotalVirtualMemory = tv >> 10 >> 10;
+      this->TotalPhysicalMemory = tp >> 10 >> 10;
+      this->AvailableVirtualMemory = av >> 10 >> 10;
+      this->AvailablePhysicalMemory =
+        (ap + buffersMem + cachedMem) >> 10 >> 10;
+    } else {
+      std::cout << "Problem parsing /proc/meminfo" << std::endl;
+      fclose(fd);
+      return false;
+    }
+  }
+  fclose(fd);
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryCygwinMemory()
+{
+#ifdef __CYGWIN__
+  // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin,
+  // see http://cygwin.com/ml/cygwin/2006-06/msg00350.html
+  // Therefore just use 4096 as the page size of Windows.
+  long m = sysconf(_SC_PHYS_PAGES);
+  if (m < 0) {
+    return false;
+  }
+  this->TotalPhysicalMemory = m >> 8;
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryAIXMemory()
+{
+#if defined(_AIX) && defined(_SC_AIX_REALMEM)
+  long c = sysconf(_SC_AIX_REALMEM);
+  if (c <= 0) {
+    return false;
+  }
+
+  this->TotalPhysicalMemory = c / 1024;
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryMemoryBySysconf()
+{
+#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
+  // Assume the mmap() granularity as returned by _SC_PAGESIZE is also
+  // the system page size. The only known system where this isn't true
+  // is Cygwin.
+  long p = sysconf(_SC_PHYS_PAGES);
+  long m = sysconf(_SC_PAGESIZE);
+
+  if (p < 0 || m < 0) {
+    return false;
+  }
+
+  // assume pagesize is a power of 2 and smaller 1 MiB
+  size_t pagediv = (1024 * 1024 / m);
+
+  this->TotalPhysicalMemory = p;
+  this->TotalPhysicalMemory /= pagediv;
+
+#if defined(_SC_AVPHYS_PAGES)
+  p = sysconf(_SC_AVPHYS_PAGES);
+  if (p < 0) {
+    return false;
+  }
+
+  this->AvailablePhysicalMemory = p;
+  this->AvailablePhysicalMemory /= pagediv;
+#endif
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+/** Query for the memory status */
+bool SystemInformationImplementation::QueryMemory()
+{
+  return this->QueryMemoryBySysconf();
+}
+
+/** */
+size_t SystemInformationImplementation::GetTotalVirtualMemory()
+{
+  return this->TotalVirtualMemory;
+}
+
+/** */
+size_t SystemInformationImplementation::GetAvailableVirtualMemory()
+{
+  return this->AvailableVirtualMemory;
+}
+
+size_t SystemInformationImplementation::GetTotalPhysicalMemory()
+{
+  return this->TotalPhysicalMemory;
+}
+
+/** */
+size_t SystemInformationImplementation::GetAvailablePhysicalMemory()
+{
+  return this->AvailablePhysicalMemory;
+}
+
+/** Get Cycle differences */
+SystemInformation::LongLong
+SystemInformationImplementation::GetCyclesDifference(DELAY_FUNC DelayFunction,
+                                                     unsigned int uiParameter)
+{
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+  unsigned __int64 stamp1, stamp2;
+
+  stamp1 = __rdtsc();
+  DelayFunction(uiParameter);
+  stamp2 = __rdtsc();
+
+  return stamp2 - stamp1;
+#elif USE_ASM_INSTRUCTIONS
+
+  unsigned int edx1, eax1;
+  unsigned int edx2, eax2;
+
+  // Calculate the frequency of the CPU instructions.
+  __try {
+    _asm {
+      push uiParameter ; push parameter param
+      mov ebx, DelayFunction ; store func in ebx
+
+      RDTSC_INSTRUCTION
+
+      mov esi, eax ; esi = eax
+      mov edi, edx ; edi = edx
+
+      call ebx ; call the delay functions
+
+      RDTSC_INSTRUCTION
+
+      pop ebx
+
+      mov edx2, edx      ; edx2 = edx
+      mov eax2, eax      ; eax2 = eax
+
+      mov edx1, edi      ; edx2 = edi
+      mov eax1, esi      ; eax2 = esi
+    }
+  } __except (1) {
+    return -1;
+  }
+
+  return ((((__int64)edx2 << 32) + eax2) - (((__int64)edx1 << 32) + eax1));
+
+#else
+  (void)DelayFunction;
+  (void)uiParameter;
+  return -1;
+#endif
+}
+
+/** Compute the delay overhead */
+void SystemInformationImplementation::DelayOverhead(unsigned int uiMS)
+{
+#if defined(_WIN32)
+  LARGE_INTEGER Frequency, StartCounter, EndCounter;
+  __int64 x;
+
+  // Get the frequency of the high performance counter.
+  if (!QueryPerformanceFrequency(&Frequency)) {
+    return;
+  }
+  x = Frequency.QuadPart / 1000 * uiMS;
+
+  // Get the starting position of the counter.
+  QueryPerformanceCounter(&StartCounter);
+
+  do {
+    // Get the ending position of the counter.
+    QueryPerformanceCounter(&EndCounter);
+  } while (EndCounter.QuadPart - StartCounter.QuadPart == x);
+#endif
+  (void)uiMS;
+}
+
+/** Works only for windows */
+bool SystemInformationImplementation::IsSMTSupported()
+{
+  return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical > 1;
+}
+
+/** Return the APIC Id. Works only for windows. */
+unsigned char SystemInformationImplementation::GetAPICId()
+{
+  int Regs[4] = { 0, 0, 0, 0 };
+
+#if USE_CPUID
+  if (!this->IsSMTSupported()) {
+    return static_cast<unsigned char>(-1); // HT not supported
+  }                                        // Logical processor = 1
+  call_cpuid(1, Regs);
+#endif
+
+  return static_cast<unsigned char>((Regs[1] & INITIAL_APIC_ID_BITS) >> 24);
+}
+
+/** Count the number of CPUs. Works only on windows. */
+void SystemInformationImplementation::CPUCountWindows()
+{
+#if defined(_WIN32)
+  this->NumberOfPhysicalCPU = 0;
+  this->NumberOfLogicalCPU = 0;
+
+  typedef BOOL(WINAPI * GetLogicalProcessorInformationType)(
+    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
+  static GetLogicalProcessorInformationType pGetLogicalProcessorInformation =
+    (GetLogicalProcessorInformationType)GetProcAddress(
+      GetModuleHandleW(L"kernel32"), "GetLogicalProcessorInformation");
+
+  if (!pGetLogicalProcessorInformation) {
+    // Fallback to approximate implementation on ancient Windows versions.
+    SYSTEM_INFO info;
+    ZeroMemory(&info, sizeof(info));
+    GetSystemInfo(&info);
+    this->NumberOfPhysicalCPU =
+      static_cast<unsigned int>(info.dwNumberOfProcessors);
+    this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
+    return;
+  }
+
+  std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> ProcInfo;
+  {
+    DWORD Length = 0;
+    DWORD rc = pGetLogicalProcessorInformation(NULL, &Length);
+    assert(FALSE == rc);
+    (void)rc; // Silence unused variable warning in Borland C++ 5.81
+    assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
+    ProcInfo.resize(Length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
+    rc = pGetLogicalProcessorInformation(&ProcInfo[0], &Length);
+    assert(rc != FALSE);
+    (void)rc; // Silence unused variable warning in Borland C++ 5.81
+  }
+
+  typedef std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION>::iterator
+    pinfoIt_t;
+  for (pinfoIt_t it = ProcInfo.begin(); it != ProcInfo.end(); ++it) {
+    SYSTEM_LOGICAL_PROCESSOR_INFORMATION PInfo = *it;
+    if (PInfo.Relationship != RelationProcessorCore) {
+      continue;
+    }
+
+    std::bitset<std::numeric_limits<ULONG_PTR>::digits> ProcMask(
+      (unsigned long long)PInfo.ProcessorMask);
+    unsigned int count = (unsigned int)ProcMask.count();
+    if (count == 0) { // I think this should never happen, but just to be safe.
+      continue;
+    }
+    this->NumberOfPhysicalCPU++;
+    this->NumberOfLogicalCPU += (unsigned int)count;
+    this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = count;
+  }
+  this->NumberOfPhysicalCPU = std::max(1u, this->NumberOfPhysicalCPU);
+  this->NumberOfLogicalCPU = std::max(1u, this->NumberOfLogicalCPU);
+#else
+#endif
+}
+
+/** Return the number of logical CPUs on the system */
+unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU()
+{
+  return this->NumberOfLogicalCPU;
+}
+
+/** Return the number of physical CPUs on the system */
+unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU()
+{
+  return this->NumberOfPhysicalCPU;
+}
+
+/** For Mac use sysctlbyname calls to find system info */
+bool SystemInformationImplementation::ParseSysCtl()
+{
+#if defined(__APPLE__)
+  char retBuf[128];
+  int err = 0;
+  uint64_t value = 0;
+  size_t len = sizeof(value);
+  sysctlbyname("hw.memsize", &value, &len, NULL, 0);
+  this->TotalPhysicalMemory = static_cast<size_t>(value / 1048576);
+
+  // Parse values for Mac
+  this->AvailablePhysicalMemory = 0;
+  vm_statistics_data_t vmstat;
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+  if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat,
+                      &count) == KERN_SUCCESS) {
+    len = sizeof(value);
+    err = sysctlbyname("hw.pagesize", &value, &len, NULL, 0);
+    int64_t available_memory = vmstat.free_count * value;
+    this->AvailablePhysicalMemory =
+      static_cast<size_t>(available_memory / 1048576);
+  }
+
+#ifdef VM_SWAPUSAGE
+  // Virtual memory.
+  int mib[2] = { CTL_VM, VM_SWAPUSAGE };
+  size_t miblen = sizeof(mib) / sizeof(mib[0]);
+  struct xsw_usage swap;
+  len = sizeof(swap);
+  err = sysctl(mib, miblen, &swap, &len, NULL, 0);
+  if (err == 0) {
+    this->AvailableVirtualMemory =
+      static_cast<size_t>(swap.xsu_avail / 1048576);
+    this->TotalVirtualMemory = static_cast<size_t>(swap.xsu_total / 1048576);
+  }
+#else
+  this->AvailableVirtualMemory = 0;
+  this->TotalVirtualMemory = 0;
+#endif
+
+  // CPU Info
+  len = sizeof(this->NumberOfPhysicalCPU);
+  sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, NULL, 0);
+  len = sizeof(this->NumberOfLogicalCPU);
+  sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, NULL, 0);
+
+  int cores_per_package = 0;
+  len = sizeof(cores_per_package);
+  err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len,
+                     NULL, 0);
+  // That name was not found, default to 1
+  this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical =
+    err != 0 ? 1 : static_cast<unsigned char>(cores_per_package);
+
+  len = sizeof(value);
+  sysctlbyname("hw.cpufrequency", &value, &len, NULL, 0);
+  this->CPUSpeedInMHz = static_cast<float>(value) / 1000000;
+
+  // Chip family
+  len = sizeof(this->ChipID.Family);
+  // Seems only the intel chips will have this name so if this fails it is
+  // probably a PPC machine
+  err =
+    sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, NULL, 0);
+  if (err != 0) // Go back to names we know but are less descriptive
+  {
+    this->ChipID.Family = 0;
+    ::memset(retBuf, 0, 128);
+    len = 32;
+    err = sysctlbyname("hw.machine", &retBuf, &len, NULL, 0);
+    std::string machineBuf(retBuf);
+    if (machineBuf.find_first_of("Power") != std::string::npos) {
+      this->ChipID.Vendor = "IBM";
+      len = sizeof(this->ChipID.Family);
+      err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, NULL, 0);
+      len = sizeof(this->ChipID.Model);
+      err = sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, NULL, 0);
+      this->FindManufacturer();
+    }
+  } else // Should be an Intel Chip.
+  {
+    len = sizeof(this->ChipID.Family);
+    err =
+      sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, NULL, 0);
+
+    ::memset(retBuf, 0, 128);
+    len = 128;
+    err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, NULL, 0);
+    // Chip Vendor
+    this->ChipID.Vendor = retBuf;
+    this->FindManufacturer();
+
+    // Chip Model
+    len = sizeof(value);
+    err = sysctlbyname("machdep.cpu.model", &value, &len, NULL, 0);
+    this->ChipID.Model = static_cast<int>(value);
+
+    // Chip Stepping
+    len = sizeof(value);
+    value = 0;
+    err = sysctlbyname("machdep.cpu.stepping", &value, &len, NULL, 0);
+    if (!err) {
+      this->ChipID.Revision = static_cast<int>(value);
+    }
+
+    // feature string
+    char* buf = 0;
+    size_t allocSize = 128;
+
+    err = 0;
+    len = 0;
+
+    // sysctlbyname() will return with err==0 && len==0 if the buffer is too
+    // small
+    while (err == 0 && len == 0) {
+      delete[] buf;
+      allocSize *= 2;
+      buf = new char[allocSize];
+      if (!buf) {
+        break;
+      }
+      buf[0] = ' ';
+      len = allocSize - 2; // keep space for leading and trailing space
+      err = sysctlbyname("machdep.cpu.features", buf + 1, &len, NULL, 0);
+    }
+    if (!err && buf && len) {
+      // now we can match every flags as space + flag + space
+      buf[len + 1] = ' ';
+      std::string cpuflags(buf, len + 2);
+
+      if ((cpuflags.find(" FPU ") != std::string::npos)) {
+        this->Features.HasFPU = true;
+      }
+      if ((cpuflags.find(" TSC ") != std::string::npos)) {
+        this->Features.HasTSC = true;
+      }
+      if ((cpuflags.find(" MMX ") != std::string::npos)) {
+        this->Features.HasMMX = true;
+      }
+      if ((cpuflags.find(" SSE ") != std::string::npos)) {
+        this->Features.HasSSE = true;
+      }
+      if ((cpuflags.find(" SSE2 ") != std::string::npos)) {
+        this->Features.HasSSE2 = true;
+      }
+      if ((cpuflags.find(" APIC ") != std::string::npos)) {
+        this->Features.HasAPIC = true;
+      }
+      if ((cpuflags.find(" CMOV ") != std::string::npos)) {
+        this->Features.HasCMOV = true;
+      }
+      if ((cpuflags.find(" MTRR ") != std::string::npos)) {
+        this->Features.HasMTRR = true;
+      }
+      if ((cpuflags.find(" ACPI ") != std::string::npos)) {
+        this->Features.HasACPI = true;
+      }
+    }
+    delete[] buf;
+  }
+
+  // brand string
+  ::memset(retBuf, 0, sizeof(retBuf));
+  len = sizeof(retBuf);
+  err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, NULL, 0);
+  if (!err) {
+    this->ChipID.ProcessorName = retBuf;
+    this->ChipID.ModelName = retBuf;
+  }
+
+  // Cache size
+  len = sizeof(value);
+  err = sysctlbyname("hw.l1icachesize", &value, &len, NULL, 0);
+  this->Features.L1CacheSize = static_cast<int>(value);
+  len = sizeof(value);
+  err = sysctlbyname("hw.l2cachesize", &value, &len, NULL, 0);
+  this->Features.L2CacheSize = static_cast<int>(value);
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+/** Extract a value from sysctl command */
+std::string SystemInformationImplementation::ExtractValueFromSysCtl(
+  const char* word)
+{
+  size_t pos = this->SysCtlBuffer.find(word);
+  if (pos != this->SysCtlBuffer.npos) {
+    pos = this->SysCtlBuffer.find(": ", pos);
+    size_t pos2 = this->SysCtlBuffer.find("\n", pos);
+    if (pos != this->SysCtlBuffer.npos && pos2 != this->SysCtlBuffer.npos) {
+      return this->SysCtlBuffer.substr(pos + 2, pos2 - pos - 2);
+    }
+  }
+  return "";
+}
+
+/** Run a given process */
+std::string SystemInformationImplementation::RunProcess(
+  std::vector<const char*> args)
+{
+  std::string buffer = "";
+
+  // Run the application
+  kwsysProcess* gp = kwsysProcess_New();
+  kwsysProcess_SetCommand(gp, &*args.begin());
+  kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1);
+
+  kwsysProcess_Execute(gp);
+
+  char* data = NULL;
+  int length;
+  double timeout = 255;
+  int pipe; // pipe id as returned by kwsysProcess_WaitForData()
+
+  while ((static_cast<void>(
+            pipe = kwsysProcess_WaitForData(gp, &data, &length, &timeout)),
+          (pipe == kwsysProcess_Pipe_STDOUT ||
+           pipe == kwsysProcess_Pipe_STDERR))) // wait for 1s
+  {
+    buffer.append(data, length);
+  }
+  kwsysProcess_WaitForExit(gp, 0);
+
+  int result = 0;
+  switch (kwsysProcess_GetState(gp)) {
+    case kwsysProcess_State_Exited: {
+      result = kwsysProcess_GetExitValue(gp);
+    } break;
+    case kwsysProcess_State_Error: {
+      std::cerr << "Error: Could not run " << args[0] << ":\n";
+      std::cerr << kwsysProcess_GetErrorString(gp) << "\n";
+    } break;
+    case kwsysProcess_State_Exception: {
+      std::cerr << "Error: " << args[0] << " terminated with an exception: "
+                << kwsysProcess_GetExceptionString(gp) << "\n";
+    } break;
+    case kwsysProcess_State_Starting:
+    case kwsysProcess_State_Executing:
+    case kwsysProcess_State_Expired:
+    case kwsysProcess_State_Killed: {
+      // Should not get here.
+      std::cerr << "Unexpected ending state after running " << args[0]
+                << std::endl;
+    } break;
+  }
+  kwsysProcess_Delete(gp);
+  if (result) {
+    std::cerr << "Error " << args[0] << " returned :" << result << "\n";
+  }
+  return buffer;
+}
+
+std::string SystemInformationImplementation::ParseValueFromKStat(
+  const char* arguments)
+{
+  std::vector<const char*> args;
+  args.clear();
+  args.push_back("kstat");
+  args.push_back("-p");
+
+  std::string command = arguments;
+  size_t start = command.npos;
+  size_t pos = command.find(' ', 0);
+  while (pos != command.npos) {
+    bool inQuotes = false;
+    // Check if we are between quotes
+    size_t b0 = command.find('"', 0);
+    size_t b1 = command.find('"', b0 + 1);
+    while (b0 != command.npos && b1 != command.npos && b1 > b0) {
+      if (pos > b0 && pos < b1) {
+        inQuotes = true;
+        break;
+      }
+      b0 = command.find('"', b1 + 1);
+      b1 = command.find('"', b0 + 1);
+    }
+
+    if (!inQuotes) {
+      std::string arg = command.substr(start + 1, pos - start - 1);
+
+      // Remove the quotes if any
+      size_t quotes = arg.find('"');
+      while (quotes != arg.npos) {
+        arg.erase(quotes, 1);
+        quotes = arg.find('"');
+      }
+      args.push_back(arg.c_str());
+      start = pos;
+    }
+    pos = command.find(' ', pos + 1);
+  }
+  std::string lastArg = command.substr(start + 1, command.size() - start - 1);
+  args.push_back(lastArg.c_str());
+
+  args.push_back(0);
+
+  std::string buffer = this->RunProcess(args);
+
+  std::string value = "";
+  for (size_t i = buffer.size() - 1; i > 0; i--) {
+    if (buffer[i] == ' ' || buffer[i] == '\t') {
+      break;
+    }
+    if (buffer[i] != '\n' && buffer[i] != '\r') {
+      std::string val = value;
+      value = buffer[i];
+      value += val;
+    }
+  }
+  return value;
+}
+
+/** Querying for system information from Solaris */
+bool SystemInformationImplementation::QuerySolarisMemory()
+{
+#if defined(__SVR4) && defined(__sun)
+// Solaris allows querying this value by sysconf, but if this is
+// a 32 bit process on a 64 bit host the returned memory will be
+// limited to 4GiB. So if this is a 32 bit process or if the sysconf
+// method fails use the kstat interface.
+#if SIZEOF_VOID_P == 8
+  if (this->QueryMemoryBySysconf()) {
+    return true;
+  }
+#endif
+
+  char* tail;
+  unsigned long totalMemory =
+    strtoul(this->ParseValueFromKStat("-s physmem").c_str(), &tail, 0);
+  this->TotalPhysicalMemory = totalMemory / 128;
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QuerySolarisProcessor()
+{
+  if (!this->QueryProcessorBySysconf()) {
+    return false;
+  }
+
+  // Parse values
+  this->CPUSpeedInMHz = static_cast<float>(
+    atoi(this->ParseValueFromKStat("-s clock_MHz").c_str()));
+
+  // Chip family
+  this->ChipID.Family = 0;
+
+  // Chip Model
+  this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type");
+  this->ChipID.Model = 0;
+
+  // Chip Vendor
+  if (this->ChipID.ProcessorName != "i386") {
+    this->ChipID.Vendor = "Sun";
+    this->FindManufacturer();
+  }
+
+  return true;
+}
+
+/** Querying for system information from Haiku OS */
+bool SystemInformationImplementation::QueryHaikuInfo()
+{
+#if defined(__HAIKU__)
+
+  // CPU count
+  system_info info;
+  get_system_info(&info);
+  this->NumberOfPhysicalCPU = info.cpu_count;
+
+  // CPU speed
+  uint32 topologyNodeCount = 0;
+  cpu_topology_node_info* topology = 0;
+  get_cpu_topology_info(0, &topologyNodeCount);
+  if (topologyNodeCount != 0)
+    topology = new cpu_topology_node_info[topologyNodeCount];
+  get_cpu_topology_info(topology, &topologyNodeCount);
+
+  for (uint32 i = 0; i < topologyNodeCount; i++) {
+    if (topology[i].type == B_TOPOLOGY_CORE) {
+      this->CPUSpeedInMHz =
+        topology[i].data.core.default_frequency / 1000000.0f;
+      break;
+    }
+  }
+
+  delete[] topology;
+
+  // Physical Memory
+  this->TotalPhysicalMemory = (info.max_pages * B_PAGE_SIZE) / (1024 * 1024);
+  this->AvailablePhysicalMemory = this->TotalPhysicalMemory -
+    ((info.used_pages * B_PAGE_SIZE) / (1024 * 1024));
+
+  // NOTE: get_system_info_etc is currently a private call so just set to 0
+  // until it becomes public
+  this->TotalVirtualMemory = 0;
+  this->AvailableVirtualMemory = 0;
+
+  // Retrieve cpuid_info union for cpu 0
+  cpuid_info cpu_info;
+  get_cpuid(&cpu_info, 0, 0);
+
+  // Chip Vendor
+  // Use a temporary buffer so that we can add NULL termination to the string
+  char vbuf[13];
+  strncpy(vbuf, cpu_info.eax_0.vendor_id, 12);
+  vbuf[12] = '\0';
+  this->ChipID.Vendor = vbuf;
+
+  this->FindManufacturer();
+
+  // Retrieve cpuid_info union for cpu 0 this time using a register value of 1
+  get_cpuid(&cpu_info, 1, 0);
+
+  this->NumberOfLogicalCPU = cpu_info.eax_1.logical_cpus;
+
+  // Chip type
+  this->ChipID.Type = cpu_info.eax_1.type;
+
+  // Chip family
+  this->ChipID.Family = cpu_info.eax_1.family;
+
+  // Chip Model
+  this->ChipID.Model = cpu_info.eax_1.model;
+
+  // Chip Revision
+  this->ChipID.Revision = cpu_info.eax_1.stepping;
+
+  // Chip Extended Family
+  this->ChipID.ExtendedFamily = cpu_info.eax_1.extended_family;
+
+  // Chip Extended Model
+  this->ChipID.ExtendedModel = cpu_info.eax_1.extended_model;
+
+  // Get ChipID.ProcessorName from other information already gathered
+  this->RetrieveClassicalCPUIdentity();
+
+  // Cache size
+  this->Features.L1CacheSize = 0;
+  this->Features.L2CacheSize = 0;
+
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryQNXMemory()
+{
+#if defined(__QNX__)
+  std::string buffer;
+  std::vector<const char*> args;
+  args.clear();
+
+  args.push_back("showmem");
+  args.push_back("-S");
+  args.push_back(0);
+  buffer = this->RunProcess(args);
+  args.clear();
+
+  size_t pos = buffer.find("System RAM:");
+  if (pos == buffer.npos)
+    return false;
+  pos = buffer.find(":", pos);
+  size_t pos2 = buffer.find("M (", pos);
+  if (pos2 == buffer.npos)
+    return false;
+
+  pos++;
+  while (buffer[pos] == ' ')
+    pos++;
+
+  this->TotalPhysicalMemory = atoi(buffer.substr(pos, pos2 - pos).c_str());
+  return true;
+#endif
+  return false;
+}
+
+bool SystemInformationImplementation::QueryBSDMemory()
+{
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
+  defined(__DragonFly__)
+  int ctrl[2] = { CTL_HW, HW_PHYSMEM };
+#if defined(HW_PHYSMEM64)
+  int64_t k;
+  ctrl[1] = HW_PHYSMEM64;
+#else
+  int k;
+#endif
+  size_t sz = sizeof(k);
+
+  if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) {
+    return false;
+  }
+
+  this->TotalPhysicalMemory = k >> 10 >> 10;
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryQNXProcessor()
+{
+#if defined(__QNX__)
+  // the output on my QNX 6.4.1 looks like this:
+  // Processor1: 686 Pentium II Stepping 3 2175MHz FPU
+  std::string buffer;
+  std::vector<const char*> args;
+  args.clear();
+
+  args.push_back("pidin");
+  args.push_back("info");
+  args.push_back(0);
+  buffer = this->RunProcess(args);
+  args.clear();
+
+  size_t pos = buffer.find("Processor1:");
+  if (pos == buffer.npos)
+    return false;
+
+  size_t pos2 = buffer.find("MHz", pos);
+  if (pos2 == buffer.npos)
+    return false;
+
+  size_t pos3 = pos2;
+  while (buffer[pos3] != ' ')
+    --pos3;
+
+  this->CPUSpeedInMHz = atoi(buffer.substr(pos3 + 1, pos2 - pos3 - 1).c_str());
+
+  pos2 = buffer.find(" Stepping", pos);
+  if (pos2 != buffer.npos) {
+    pos2 = buffer.find(" ", pos2 + 1);
+    if (pos2 != buffer.npos && pos2 < pos3) {
+      this->ChipID.Revision =
+        atoi(buffer.substr(pos2 + 1, pos3 - pos2).c_str());
+    }
+  }
+
+  this->NumberOfPhysicalCPU = 0;
+  do {
+    pos = buffer.find("\nProcessor", pos + 1);
+    ++this->NumberOfPhysicalCPU;
+  } while (pos != buffer.npos);
+  this->NumberOfLogicalCPU = 1;
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryBSDProcessor()
+{
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
+  defined(__DragonFly__)
+  int k;
+  size_t sz = sizeof(k);
+  int ctrl[2] = { CTL_HW, HW_NCPU };
+
+  if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) {
+    return false;
+  }
+
+  this->NumberOfPhysicalCPU = k;
+  this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
+
+#if defined(HW_CPUSPEED)
+  ctrl[1] = HW_CPUSPEED;
+
+  if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) {
+    return false;
+  }
+
+  this->CPUSpeedInMHz = (float)k;
+#endif
+
+#if defined(CPU_SSE)
+  ctrl[0] = CTL_MACHDEP;
+  ctrl[1] = CPU_SSE;
+
+  if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) {
+    return false;
+  }
+
+  this->Features.HasSSE = (k > 0);
+#endif
+
+#if defined(CPU_SSE2)
+  ctrl[0] = CTL_MACHDEP;
+  ctrl[1] = CPU_SSE2;
+
+  if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) {
+    return false;
+  }
+
+  this->Features.HasSSE2 = (k > 0);
+#endif
+
+#if defined(CPU_CPUVENDOR)
+  ctrl[0] = CTL_MACHDEP;
+  ctrl[1] = CPU_CPUVENDOR;
+  char vbuf[25];
+  ::memset(vbuf, 0, sizeof(vbuf));
+  sz = sizeof(vbuf) - 1;
+  if (sysctl(ctrl, 2, vbuf, &sz, NULL, 0) != 0) {
+    return false;
+  }
+
+  this->ChipID.Vendor = vbuf;
+  this->FindManufacturer();
+#endif
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryHPUXMemory()
+{
+#if defined(__hpux)
+  unsigned long tv = 0;
+  unsigned long tp = 0;
+  unsigned long av = 0;
+  unsigned long ap = 0;
+  struct pst_static pst;
+  struct pst_dynamic pdy;
+
+  unsigned long ps = 0;
+  if (pstat_getstatic(&pst, sizeof(pst), (size_t)1, 0) == -1) {
+    return false;
+  }
+
+  ps = pst.page_size;
+  tp = pst.physical_memory * ps;
+  tv = (pst.physical_memory + pst.pst_maxmem) * ps;
+  if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t)1, 0) == -1) {
+    return false;
+  }
+
+  ap = tp - pdy.psd_rm * ps;
+  av = tv - pdy.psd_vm;
+  this->TotalVirtualMemory = tv >> 10 >> 10;
+  this->TotalPhysicalMemory = tp >> 10 >> 10;
+  this->AvailableVirtualMemory = av >> 10 >> 10;
+  this->AvailablePhysicalMemory = ap >> 10 >> 10;
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool SystemInformationImplementation::QueryHPUXProcessor()
+{
+#if defined(__hpux)
+#if defined(KWSYS_SYS_HAS_MPCTL_H)
+  int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0);
+  if (c <= 0) {
+    return false;
+  }
+
+  this->NumberOfPhysicalCPU = c;
+  this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
+
+  long t = sysconf(_SC_CPU_VERSION);
+
+  if (t == -1) {
+    return false;
+  }
+
+  switch (t) {
+    case CPU_PA_RISC1_0:
+      this->ChipID.Vendor = "Hewlett-Packard";
+      this->ChipID.Family = 0x100;
+      break;
+    case CPU_PA_RISC1_1:
+      this->ChipID.Vendor = "Hewlett-Packard";
+      this->ChipID.Family = 0x110;
+      break;
+    case CPU_PA_RISC2_0:
+      this->ChipID.Vendor = "Hewlett-Packard";
+      this->ChipID.Family = 0x200;
+      break;
+#if defined(CPU_HP_INTEL_EM_1_0) || defined(CPU_IA64_ARCHREV_0)
+#ifdef CPU_HP_INTEL_EM_1_0
+    case CPU_HP_INTEL_EM_1_0:
+#endif
+#ifdef CPU_IA64_ARCHREV_0
+    case CPU_IA64_ARCHREV_0:
+#endif
+      this->ChipID.Vendor = "GenuineIntel";
+      this->Features.HasIA64 = true;
+      break;
+#endif
+    default:
+      return false;
+  }
+
+  this->FindManufacturer();
+
+  return true;
+#else
+  return false;
+#endif
+#else
+  return false;
+#endif
+}
+
+/** Query the operating system information */
+bool SystemInformationImplementation::QueryOSInformation()
+{
+#if defined(_WIN32)
+
+  this->OSName = "Windows";
+
+  OSVERSIONINFOEXW osvi;
+  BOOL bIsWindows64Bit;
+  BOOL bOsVersionInfoEx;
+  char operatingSystem[256];
+
+  // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
+  ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXW));
+  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(push)
+#ifdef __INTEL_COMPILER
+#pragma warning(disable : 1478)
+#else
+#pragma warning(disable : 4996)
+#endif
+#endif
+  bOsVersionInfoEx = GetVersionExW((OSVERSIONINFOW*)&osvi);
+  if (!bOsVersionInfoEx) {
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
+    if (!GetVersionExW((OSVERSIONINFOW*)&osvi)) {
+      return false;
+    }
+  }
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(pop)
+#endif
+
+  switch (osvi.dwPlatformId) {
+    case VER_PLATFORM_WIN32_NT:
+      // Test for the product.
+      if (osvi.dwMajorVersion <= 4) {
+        this->OSRelease = "NT";
+      }
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
+        this->OSRelease = "2000";
+      }
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+        this->OSRelease = "XP";
+      }
+      // XP Professional x64
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
+        this->OSRelease = "XP";
+      }
+#ifdef VER_NT_WORKSTATION
+      // Test for product type.
+      if (bOsVersionInfoEx) {
+        if (osvi.wProductType == VER_NT_WORKSTATION) {
+          if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
+            this->OSRelease = "Vista";
+          }
+          if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) {
+            this->OSRelease = "7";
+          }
+// VER_SUITE_PERSONAL may not be defined
+#ifdef VER_SUITE_PERSONAL
+          else {
+            if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
+              this->OSRelease += " Personal";
+            } else {
+              this->OSRelease += " Professional";
+            }
+          }
+#endif
+        } else if (osvi.wProductType == VER_NT_SERVER) {
+          // Check for .NET Server instead of Windows XP.
+          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+            this->OSRelease = ".NET";
+          }
+
+          // Continue with the type detection.
+          if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+            this->OSRelease += " DataCenter Server";
+          } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+            this->OSRelease += " Advanced Server";
+          } else {
+            this->OSRelease += " Server";
+          }
+        }
+
+        sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion,
+                osvi.dwBuildNumber & 0xFFFF);
+        this->OSVersion = operatingSystem;
+      } else
+#endif // VER_NT_WORKSTATION
+      {
+        HKEY hKey;
+        wchar_t szProductType[80];
+        DWORD dwBufLen;
+
+        // Query the registry to retrieve information.
+        RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                      L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0,
+                      KEY_QUERY_VALUE, &hKey);
+        RegQueryValueExW(hKey, L"ProductType", NULL, NULL,
+                         (LPBYTE)szProductType, &dwBufLen);
+        RegCloseKey(hKey);
+
+        if (lstrcmpiW(L"WINNT", szProductType) == 0) {
+          this->OSRelease += " Professional";
+        }
+        if (lstrcmpiW(L"LANMANNT", szProductType) == 0) {
+          // Decide between Windows 2000 Advanced Server and Windows .NET
+          // Enterprise Server.
+          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+            this->OSRelease += " Standard Server";
+          } else {
+            this->OSRelease += " Server";
+          }
+        }
+        if (lstrcmpiW(L"SERVERNT", szProductType) == 0) {
+          // Decide between Windows 2000 Advanced Server and Windows .NET
+          // Enterprise Server.
+          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+            this->OSRelease += " Enterprise Server";
+          } else {
+            this->OSRelease += " Advanced Server";
+          }
+        }
+      }
+
+      // Display version, service pack (if any), and build number.
+      if (osvi.dwMajorVersion <= 4) {
+        // NB: NT 4.0 and earlier.
+        sprintf(operatingSystem, "version %ld.%ld %ls (Build %ld)",
+                osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion,
+                osvi.dwBuildNumber & 0xFFFF);
+        this->OSVersion = operatingSystem;
+      } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+        // Windows XP and .NET server.
+        typedef BOOL(CALLBACK * LPFNPROC)(HANDLE, BOOL*);
+        HINSTANCE hKernelDLL;
+        LPFNPROC DLLProc;
+
+        // Load the Kernel32 DLL.
+        hKernelDLL = LoadLibraryW(L"kernel32");
+        if (hKernelDLL != NULL) {
+          // Only XP and .NET Server support IsWOW64Process so... Load
+          // dynamically!
+          DLLProc = (LPFNPROC)GetProcAddress(hKernelDLL, "IsWow64Process");
+
+          // If the function address is valid, call the function.
+          if (DLLProc != NULL)
+            (DLLProc)(GetCurrentProcess(), &bIsWindows64Bit);
+          else
+            bIsWindows64Bit = false;
+
+          // Free the DLL module.
+          FreeLibrary(hKernelDLL);
+        }
+      } else {
+        // Windows 2000 and everything else.
+        sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion,
+                osvi.dwBuildNumber & 0xFFFF);
+        this->OSVersion = operatingSystem;
+      }
+      break;
+
+    case VER_PLATFORM_WIN32_WINDOWS:
+      // Test for the product.
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
+        this->OSRelease = "95";
+        if (osvi.szCSDVersion[1] == 'C') {
+          this->OSRelease += "OSR 2.5";
+        } else if (osvi.szCSDVersion[1] == 'B') {
+          this->OSRelease += "OSR 2";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
+        this->OSRelease = "98";
+        if (osvi.szCSDVersion[1] == 'A') {
+          this->OSRelease += "SE";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
+        this->OSRelease = "Me";
+      }
+      break;
+
+    case VER_PLATFORM_WIN32s:
+      this->OSRelease = "Win32s";
+      break;
+
+    default:
+      this->OSRelease = "Unknown";
+      break;
+  }
+
+  // Get the hostname
+  WORD wVersionRequested;
+  WSADATA wsaData;
+  char name[255];
+  wVersionRequested = MAKEWORD(2, 0);
+
+  if (WSAStartup(wVersionRequested, &wsaData) == 0) {
+    gethostname(name, sizeof(name));
+    WSACleanup();
+  }
+  this->Hostname = name;
+
+  const char* arch = getenv("PROCESSOR_ARCHITECTURE");
+  const char* wow64 = getenv("PROCESSOR_ARCHITEW6432");
+  if (arch) {
+    this->OSPlatform = arch;
+  }
+
+  if (wow64) {
+    // the PROCESSOR_ARCHITEW6432 is only defined when running 32bit programs
+    // on 64bit OS
+    this->OSIs64Bit = true;
+  } else if (arch) {
+    // all values other than x86 map to 64bit architectures
+    this->OSIs64Bit = (strncmp(arch, "x86", 3) != 0);
+  }
+
+#else
+
+  struct utsname unameInfo;
+  int errorFlag = uname(&unameInfo);
+  if (errorFlag == 0) {
+    this->OSName = unameInfo.sysname;
+    this->Hostname = unameInfo.nodename;
+    this->OSRelease = unameInfo.release;
+    this->OSVersion = unameInfo.version;
+    this->OSPlatform = unameInfo.machine;
+
+    // This is still insufficient to capture 64bit architecture such
+    // powerpc and possible mips and sparc
+    if (this->OSPlatform.find_first_of("64") != std::string::npos) {
+      this->OSIs64Bit = true;
+    }
+  }
+
+#ifdef __APPLE__
+  this->OSName = "Unknown Apple OS";
+  this->OSRelease = "Unknown product version";
+  this->OSVersion = "Unknown build version";
+
+  this->CallSwVers("-productName", this->OSName);
+  this->CallSwVers("-productVersion", this->OSRelease);
+  this->CallSwVers("-buildVersion", this->OSVersion);
+#endif
+
+#endif
+
+  return true;
+}
+
+int SystemInformationImplementation::CallSwVers(const char* arg,
+                                                std::string& ver)
+{
+#ifdef __APPLE__
+  std::vector<const char*> args;
+  args.push_back("sw_vers");
+  args.push_back(arg);
+  args.push_back(0);
+  ver = this->RunProcess(args);
+  this->TrimNewline(ver);
+#else
+  // avoid C4100
+  (void)arg;
+  (void)ver;
+#endif
+  return 0;
+}
+
+void SystemInformationImplementation::TrimNewline(std::string& output)
+{
+  // remove \r
+  std::string::size_type pos = 0;
+  while ((pos = output.find("\r", pos)) != std::string::npos) {
+    output.erase(pos);
+  }
+
+  // remove \n
+  pos = 0;
+  while ((pos = output.find("\n", pos)) != std::string::npos) {
+    output.erase(pos);
+  }
+}
+
+/** Return true if the machine is 64 bits */
+bool SystemInformationImplementation::Is64Bits()
+{
+  return this->OSIs64Bit;
+}
+}
diff --git a/thirdparty/KWSys/adios2sys/SystemInformation.hxx.in b/thirdparty/KWSys/adios2sys/SystemInformation.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..54e7fc10b93e8fff4a389319d934955ec4234018
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/SystemInformation.hxx.in
@@ -0,0 +1,140 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_SystemInformation_h
+#define @KWSYS_NAMESPACE@_SystemInformation_h
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <stddef.h> /* size_t */
+#include <string>
+
+namespace @KWSYS_NAMESPACE@ {
+
+// forward declare the implementation class
+class SystemInformationImplementation;
+
+class @KWSYS_NAMESPACE@_EXPORT SystemInformation
+{
+#if @KWSYS_USE_LONG_LONG@
+  typedef long long LongLong;
+#elif @KWSYS_USE___INT64@
+  typedef __int64 LongLong;
+#else
+#error "No Long Long"
+#endif
+  friend class SystemInformationImplementation;
+  SystemInformationImplementation* Implementation;
+
+public:
+  SystemInformation();
+  ~SystemInformation();
+
+  const char* GetVendorString();
+  const char* GetVendorID();
+  std::string GetTypeID();
+  std::string GetFamilyID();
+  std::string GetModelID();
+  std::string GetModelName();
+  std::string GetSteppingCode();
+  const char* GetExtendedProcessorName();
+  const char* GetProcessorSerialNumber();
+  int GetProcessorCacheSize();
+  unsigned int GetLogicalProcessorsPerPhysical();
+  float GetProcessorClockFrequency();
+  int GetProcessorAPICID();
+  int GetProcessorCacheXSize(long int);
+  bool DoesCPUSupportFeature(long int);
+
+  // returns an informative general description of the cpu
+  // on this system.
+  std::string GetCPUDescription();
+
+  const char* GetHostname();
+  std::string GetFullyQualifiedDomainName();
+
+  const char* GetOSName();
+  const char* GetOSRelease();
+  const char* GetOSVersion();
+  const char* GetOSPlatform();
+
+  int GetOSIsWindows();
+  int GetOSIsLinux();
+  int GetOSIsApple();
+
+  // returns an informative general description of the os
+  // on this system.
+  std::string GetOSDescription();
+
+  // returns if the operating system is 64bit or not.
+  bool Is64Bits();
+
+  unsigned int GetNumberOfLogicalCPU();
+  unsigned int GetNumberOfPhysicalCPU();
+
+  bool DoesCPUSupportCPUID();
+
+  // Retrieve id of the current running process
+  LongLong GetProcessId();
+
+  // Retrieve memory information in megabyte.
+  size_t GetTotalVirtualMemory();
+  size_t GetAvailableVirtualMemory();
+  size_t GetTotalPhysicalMemory();
+  size_t GetAvailablePhysicalMemory();
+
+  // returns an informative general description if the installed and
+  // available ram on this system. See the  GetHostMmeoryTotal, and
+  // Get{Host,Proc}MemoryAvailable methods for more information.
+  std::string GetMemoryDescription(const char* hostLimitEnvVarName = NULL,
+                                   const char* procLimitEnvVarName = NULL);
+
+  // Retrieve amount of physical memory installed on the system in KiB
+  // units.
+  LongLong GetHostMemoryTotal();
+
+  // Get total system RAM in units of KiB available colectivley to all
+  // processes in a process group. An example of a process group
+  // are the processes comprising an mpi program which is running in
+  // parallel. The amount of memory reported may differ from the host
+  // total if a host wide resource limit is applied. Such reource limits
+  // are reported to us via an applicaiton specified environment variable.
+  LongLong GetHostMemoryAvailable(const char* hostLimitEnvVarName = NULL);
+
+  // Get total system RAM in units of KiB available to this process.
+  // This may differ from the host available if a per-process resource
+  // limit is applied. per-process memory limits are applied on unix
+  // system via rlimit API. Resource limits that are not imposed via
+  // rlimit API may be reported to us via an application specified
+  // environment variable.
+  LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName = NULL,
+                                  const char* procLimitEnvVarName = NULL);
+
+  // Get the system RAM used by all processes on the host, in units of KiB.
+  LongLong GetHostMemoryUsed();
+
+  // Get system RAM used by this process id in units of KiB.
+  LongLong GetProcMemoryUsed();
+
+  // Return the load average of the machine or -0.0 if it cannot
+  // be determined.
+  double GetLoadAverage();
+
+  // enable/disable stack trace signal handler. In order to
+  // produce an informative stack trace the application should
+  // be dynamically linked and compiled with debug symbols.
+  static void SetStackTraceOnError(int enable);
+
+  // format and return the current program stack in a string. In
+  // order to produce an informative stack trace the application
+  // should be dynamically linked and compiled with debug symbols.
+  static std::string GetProgramStack(int firstFrame, int wholePath);
+
+  /** Run the different checks */
+  void RunCPUCheck();
+  void RunOSCheck();
+  void RunMemoryCheck();
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/SystemTools.cxx b/thirdparty/KWSys/adios2sys/SystemTools.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b6da368c1186c5761d15f4274ec90eea99af12a7
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/SystemTools.cxx
@@ -0,0 +1,4908 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifdef __osf__
+#define _OSF_SOURCE
+#define _POSIX_C_SOURCE 199506L
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+
+#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) ||          \
+                        defined(__BORLANDC__) || defined(__MINGW32__))
+#define KWSYS_WINDOWS_DIRS
+#else
+#if defined(__SUNPRO_CC)
+#include <fcntl.h>
+#endif
+#endif
+
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(RegularExpression.hxx)
+#include KWSYS_HEADER(SystemTools.hxx)
+#include KWSYS_HEADER(Directory.hxx)
+#include KWSYS_HEADER(FStream.hxx)
+#include KWSYS_HEADER(Encoding.hxx)
+
+#include <fstream>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <vector>
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Directory.hxx.in"
+#include "Encoding.hxx.in"
+#include "FStream.hxx.in"
+#include "RegularExpression.hxx.in"
+#include "SystemTools.hxx.in"
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__)
+#pragma set woff 1375 /* base class destructor not virtual */
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#ifdef __QNX__
+#include <malloc.h> /* for malloc/free on QNX */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__)
+#include <strings.h> /* for strcasecmp */
+#endif
+
+#ifdef _MSC_VER
+#define umask _umask // Note this is still umask on Borland
+#endif
+
+// support for realpath call
+#ifndef _WIN32
+#include <limits.h>
+#include <pwd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utime.h>
+#ifndef __VMS
+#include <sys/param.h>
+#include <termios.h>
+#endif
+#include <signal.h> /* sigprocmask */
+#endif
+
+// Windows API.
+#if defined(_WIN32)
+#include <windows.h>
+#include <winioctl.h>
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#endif
+#elif defined(__CYGWIN__)
+#include <windows.h>
+#undef _WIN32
+#endif
+
+#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
+extern char** environ;
+#endif
+
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+#endif
+
+// getpwnam doesn't exist on Windows and Cray Xt3/Catamount
+// same for TIOCGWINSZ
+#if defined(_WIN32) || defined(__LIBCATAMOUNT__)
+#undef HAVE_GETPWNAM
+#undef HAVE_TTY_INFO
+#else
+#define HAVE_GETPWNAM 1
+#define HAVE_TTY_INFO 1
+#endif
+
+#define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)"
+#define VTK_URL_REGEX                                                         \
+  "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/"     \
+  "(.+)?"
+
+#ifdef _MSC_VER
+#include <sys/utime.h>
+#else
+#include <utime.h>
+#endif
+
+// This is a hack to prevent warnings about these functions being
+// declared but not referenced.
+#if defined(__sgi) && !defined(__GNUC__)
+#include <sys/termios.h>
+namespace KWSYS_NAMESPACE {
+class SystemToolsHack
+{
+public:
+  enum
+  {
+    Ref1 = sizeof(cfgetospeed(0)),
+    Ref2 = sizeof(cfgetispeed(0)),
+    Ref3 = sizeof(tcgetattr(0, 0)),
+    Ref4 = sizeof(tcsetattr(0, 0, 0)),
+    Ref5 = sizeof(cfsetospeed(0, 0)),
+    Ref6 = sizeof(cfsetispeed(0, 0))
+  };
+};
+}
+#endif
+
+#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) ||          \
+                        defined(__BORLANDC__) || defined(__MINGW32__))
+#include <direct.h>
+#include <io.h>
+#define _unlink unlink
+#endif
+
+/* The maximum length of a file name.  */
+#if defined(PATH_MAX)
+#define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX
+#elif defined(MAXPATHLEN)
+#define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN
+#else
+#define KWSYS_SYSTEMTOOLS_MAXPATH 16384
+#endif
+#if defined(__WATCOMC__)
+#include <direct.h>
+#define _mkdir mkdir
+#define _rmdir rmdir
+#define _getcwd getcwd
+#define _chdir chdir
+#endif
+
+#if defined(__BEOS__) && !defined(__ZETA__)
+#include <be/kernel/OS.h>
+#include <be/storage/Path.h>
+
+// BeOS 5 doesn't have usleep(), but it has snooze(), which is identical.
+static inline void usleep(unsigned int msec)
+{
+  ::snooze(msec);
+}
+
+// BeOS 5 also doesn't have realpath(), but its C++ API offers something close.
+static inline char* realpath(const char* path, char* resolved_path)
+{
+  const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH;
+  snprintf(resolved_path, maxlen, "%s", path);
+  BPath normalized(resolved_path, NULL, true);
+  const char* resolved = normalized.Path();
+  if (resolved != NULL) // NULL == No such file.
+  {
+    if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) {
+      return resolved_path;
+    }
+  }
+  return NULL; // something went wrong.
+}
+#endif
+
+#ifdef _WIN32
+static time_t windows_filetime_to_posix_time(const FILETIME& ft)
+{
+  LARGE_INTEGER date;
+  date.HighPart = ft.dwHighDateTime;
+  date.LowPart = ft.dwLowDateTime;
+
+  // removes the diff between 1970 and 1601
+  date.QuadPart -= ((LONGLONG)(369 * 365 + 89) * 24 * 3600 * 10000000);
+
+  // converts back from 100-nanoseconds to seconds
+  return date.QuadPart / 10000000;
+}
+#endif
+
+#ifdef KWSYS_WINDOWS_DIRS
+#include <wctype.h>
+
+inline int Mkdir(const std::string& dir)
+{
+  return _wmkdir(
+    KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str());
+}
+inline int Rmdir(const std::string& dir)
+{
+  return _wrmdir(
+    KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str());
+}
+inline const char* Getcwd(char* buf, unsigned int len)
+{
+  std::vector<wchar_t> w_buf(len);
+  if (_wgetcwd(&w_buf[0], len)) {
+    // make sure the drive letter is capital
+    if (wcslen(&w_buf[0]) > 1 && w_buf[1] == L':') {
+      w_buf[0] = towupper(w_buf[0]);
+    }
+    std::string tmp = KWSYS_NAMESPACE::Encoding::ToNarrow(&w_buf[0]);
+    strcpy(buf, tmp.c_str());
+    return buf;
+  }
+  return 0;
+}
+inline int Chdir(const std::string& dir)
+{
+#if defined(__BORLANDC__)
+  return chdir(dir.c_str());
+#else
+  return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str());
+#endif
+}
+inline void Realpath(const std::string& path, std::string& resolved_path,
+                     std::string* errorMessage = 0)
+{
+  std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path);
+  wchar_t* ptemp;
+  wchar_t fullpath[MAX_PATH];
+  DWORD bufferLen = GetFullPathNameW(
+    tmp.c_str(), sizeof(fullpath) / sizeof(fullpath[0]), fullpath, &ptemp);
+  if (bufferLen < sizeof(fullpath) / sizeof(fullpath[0])) {
+    resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath);
+    KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path);
+  } else if (errorMessage) {
+    if (bufferLen) {
+      *errorMessage = "Destination path buffer size too small.";
+    } else if (unsigned int errorId = GetLastError()) {
+      LPSTR message = NULL;
+      DWORD size = FormatMessageA(
+        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+          FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        (LPSTR)&message, 0, NULL);
+      *errorMessage = std::string(message, size);
+      LocalFree(message);
+    } else {
+      *errorMessage = "Unknown error.";
+    }
+
+    resolved_path = "";
+  } else {
+    resolved_path = path;
+  }
+}
+#else
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+inline int Mkdir(const std::string& dir)
+{
+  return mkdir(dir.c_str(), 00777);
+}
+inline int Rmdir(const std::string& dir)
+{
+  return rmdir(dir.c_str());
+}
+inline const char* Getcwd(char* buf, unsigned int len)
+{
+  return getcwd(buf, len);
+}
+
+inline int Chdir(const std::string& dir)
+{
+  return chdir(dir.c_str());
+}
+inline void Realpath(const std::string& path, std::string& resolved_path,
+                     std::string* errorMessage = 0)
+{
+  char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH];
+
+  errno = 0;
+  char* ret = realpath(path.c_str(), resolved_name);
+  if (ret) {
+    resolved_path = ret;
+  } else if (errorMessage) {
+    if (errno) {
+      *errorMessage = strerror(errno);
+    } else {
+      *errorMessage = "Unknown error.";
+    }
+
+    resolved_path = "";
+  } else {
+    // if path resolution fails, return what was passed in
+    resolved_path = path;
+  }
+}
+#endif
+
+#if !defined(_WIN32) && defined(__COMO__)
+// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE.
+extern "C" {
+extern FILE* popen(__const char* __command, __const char* __modes) __THROW;
+extern int pclose(FILE* __stream) __THROW;
+extern char* realpath(__const char* __restrict __name,
+                      char* __restrict __resolved) __THROW;
+extern char* strdup(__const char* __s) __THROW;
+extern int putenv(char* __string) __THROW;
+}
+#endif
+
+namespace KWSYS_NAMESPACE {
+
+double SystemTools::GetTime(void)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  FILETIME ft;
+  GetSystemTimeAsFileTime(&ft);
+  return (429.4967296 * ft.dwHighDateTime + 0.0000001 * ft.dwLowDateTime -
+          11644473600.0);
+#else
+  struct timeval t;
+  gettimeofday(&t, 0);
+  return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec);
+#endif
+}
+
+class SystemToolsTranslationMap : public std::map<std::string, std::string>
+{
+};
+
+/* Type of character storing the environment.  */
+#if defined(_WIN32)
+typedef wchar_t envchar;
+#else
+typedef char envchar;
+#endif
+
+/* Order by environment key only (VAR from VAR=VALUE).  */
+struct kwsysEnvCompare
+{
+  bool operator()(const envchar* l, const envchar* r) const
+  {
+#if defined(_WIN32)
+    const wchar_t* leq = wcschr(l, L'=');
+    const wchar_t* req = wcschr(r, L'=');
+    size_t llen = leq ? (leq - l) : wcslen(l);
+    size_t rlen = req ? (req - r) : wcslen(r);
+    if (llen == rlen) {
+      return wcsncmp(l, r, llen) < 0;
+    } else {
+      return wcscmp(l, r) < 0;
+    }
+#else
+    const char* leq = strchr(l, '=');
+    const char* req = strchr(r, '=');
+    size_t llen = leq ? (leq - l) : strlen(l);
+    size_t rlen = req ? (req - r) : strlen(r);
+    if (llen == rlen) {
+      return strncmp(l, r, llen) < 0;
+    } else {
+      return strcmp(l, r) < 0;
+    }
+#endif
+  }
+};
+
+class kwsysEnvSet : public std::set<const envchar*, kwsysEnvCompare>
+{
+public:
+  class Free
+  {
+    const envchar* Env;
+
+  public:
+    Free(const envchar* env)
+      : Env(env)
+    {
+    }
+    ~Free() { free(const_cast<envchar*>(this->Env)); }
+  };
+
+  const envchar* Release(const envchar* env)
+  {
+    const envchar* old = 0;
+    iterator i = this->find(env);
+    if (i != this->end()) {
+      old = *i;
+      this->erase(i);
+    }
+    return old;
+  }
+};
+
+#ifdef _WIN32
+struct SystemToolsPathCaseCmp
+{
+  bool operator()(std::string const& l, std::string const& r) const
+  {
+#ifdef _MSC_VER
+    return _stricmp(l.c_str(), r.c_str()) < 0;
+#elif defined(__GNUC__)
+    return strcasecmp(l.c_str(), r.c_str()) < 0;
+#else
+    return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0;
+#endif
+  }
+};
+
+class SystemToolsPathCaseMap
+  : public std::map<std::string, std::string, SystemToolsPathCaseCmp>
+{
+};
+
+class SystemToolsEnvMap : public std::map<std::string, std::string>
+{
+};
+#endif
+
+// adds the elements of the env variable path to the arg passed in
+void SystemTools::GetPath(std::vector<std::string>& path, const char* env)
+{
+  size_t const old_size = path.size();
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  const char pathSep = ';';
+#else
+  const char pathSep = ':';
+#endif
+  if (!env) {
+    env = "PATH";
+  }
+  std::string pathEnv;
+  if (!SystemTools::GetEnv(env, pathEnv)) {
+    return;
+  }
+
+  // A hack to make the below algorithm work.
+  if (!pathEnv.empty() && *pathEnv.rbegin() != pathSep) {
+    pathEnv += pathSep;
+  }
+  std::string::size_type start = 0;
+  bool done = false;
+  while (!done) {
+    std::string::size_type endpos = pathEnv.find(pathSep, start);
+    if (endpos != std::string::npos) {
+      path.push_back(pathEnv.substr(start, endpos - start));
+      start = endpos + 1;
+    } else {
+      done = true;
+    }
+  }
+  for (std::vector<std::string>::iterator i = path.begin() + old_size;
+       i != path.end(); ++i) {
+    SystemTools::ConvertToUnixSlashes(*i);
+  }
+}
+
+const char* SystemTools::GetEnvImpl(const char* key)
+{
+  const char* v = 0;
+#if defined(_WIN32)
+  std::string env;
+  if (SystemTools::GetEnv(key, env)) {
+    std::string& menv = (*SystemTools::EnvMap)[key];
+    menv = env;
+    v = menv.c_str();
+  }
+#else
+  v = getenv(key);
+#endif
+  return v;
+}
+
+const char* SystemTools::GetEnv(const char* key)
+{
+  return SystemTools::GetEnvImpl(key);
+}
+
+const char* SystemTools::GetEnv(const std::string& key)
+{
+  return SystemTools::GetEnvImpl(key.c_str());
+}
+
+bool SystemTools::GetEnv(const char* key, std::string& result)
+{
+#if defined(_WIN32)
+  const std::wstring wkey = Encoding::ToWide(key);
+  const wchar_t* wv = _wgetenv(wkey.c_str());
+  if (wv) {
+    result = Encoding::ToNarrow(wv);
+    return true;
+  }
+#else
+  const char* v = getenv(key);
+  if (v) {
+    result = v;
+    return true;
+  }
+#endif
+  return false;
+}
+
+bool SystemTools::GetEnv(const std::string& key, std::string& result)
+{
+  return SystemTools::GetEnv(key.c_str(), result);
+}
+
+bool SystemTools::HasEnv(const char* key)
+{
+#if defined(_WIN32)
+  const std::wstring wkey = Encoding::ToWide(key);
+  const wchar_t* v = _wgetenv(wkey.c_str());
+#else
+  const char* v = getenv(key);
+#endif
+  return v != 0;
+}
+
+bool SystemTools::HasEnv(const std::string& key)
+{
+  return SystemTools::HasEnv(key.c_str());
+}
+
+//----------------------------------------------------------------------------
+
+#if KWSYS_CXX_HAS_UNSETENV
+/* unsetenv("A") removes A from the environment.
+   On older platforms it returns void instead of int.  */
+static int kwsysUnPutEnv(const std::string& env)
+{
+  size_t pos = env.find('=');
+  if (pos != env.npos) {
+    std::string name = env.substr(0, pos);
+    unsetenv(name.c_str());
+  } else {
+    unsetenv(env.c_str());
+  }
+  return 0;
+}
+
+#elif defined(__CYGWIN__) || defined(__GLIBC__)
+/* putenv("A") removes A from the environment.  It must not put the
+   memory in the environment because it does not have any "=" syntax.  */
+static int kwsysUnPutEnv(const std::string& env)
+{
+  int err = 0;
+  size_t pos = env.find('=');
+  size_t const len = pos == env.npos ? env.size() : pos;
+  size_t const sz = len + 1;
+  char local_buf[256];
+  char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf;
+  if (!buf) {
+    return -1;
+  }
+  strncpy(buf, env.c_str(), len);
+  buf[len] = 0;
+  if (putenv(buf) < 0 && errno != EINVAL) {
+    err = errno;
+  }
+  if (buf != local_buf) {
+    free(buf);
+  }
+  if (err) {
+    errno = err;
+    return -1;
+  }
+  return 0;
+}
+
+#elif defined(_WIN32)
+/* putenv("A=") places "A=" in the environment, which is as close to
+   removal as we can get with the putenv API.  We have to leak the
+   most recent value placed in the environment for each variable name
+   on program exit in case exit routines access it.  */
+
+static kwsysEnvSet kwsysUnPutEnvSet;
+
+static int kwsysUnPutEnv(std::string const& env)
+{
+  std::wstring wEnv = Encoding::ToWide(env);
+  size_t const pos = wEnv.find('=');
+  size_t const len = pos == wEnv.npos ? wEnv.size() : pos;
+  wEnv.resize(len + 1, L'=');
+  wchar_t* newEnv = _wcsdup(wEnv.c_str());
+  if (!newEnv) {
+    return -1;
+  }
+  kwsysEnvSet::Free oldEnv(kwsysUnPutEnvSet.Release(newEnv));
+  kwsysUnPutEnvSet.insert(newEnv);
+  return _wputenv(newEnv);
+}
+
+#else
+/* Manipulate the "environ" global directly.  */
+static int kwsysUnPutEnv(const std::string& env)
+{
+  size_t pos = env.find('=');
+  size_t const len = pos == env.npos ? env.size() : pos;
+  int in = 0;
+  int out = 0;
+  while (environ[in]) {
+    if (strlen(environ[in]) > len && environ[in][len] == '=' &&
+        strncmp(env.c_str(), environ[in], len) == 0) {
+      ++in;
+    } else {
+      environ[out++] = environ[in++];
+    }
+  }
+  while (out < in) {
+    environ[out++] = 0;
+  }
+  return 0;
+}
+#endif
+
+//----------------------------------------------------------------------------
+
+#if KWSYS_CXX_HAS_SETENV
+
+/* setenv("A", "B", 1) will set A=B in the environment and makes its
+   own copies of the strings.  */
+bool SystemTools::PutEnv(const std::string& env)
+{
+  size_t pos = env.find('=');
+  if (pos != env.npos) {
+    std::string name = env.substr(0, pos);
+    return setenv(name.c_str(), env.c_str() + pos + 1, 1) == 0;
+  } else {
+    return kwsysUnPutEnv(env) == 0;
+  }
+}
+
+bool SystemTools::UnPutEnv(const std::string& env)
+{
+  return kwsysUnPutEnv(env) == 0;
+}
+
+#else
+
+/* putenv("A=B") will set A=B in the environment.  Most putenv implementations
+   put their argument directly in the environment.  They never free the memory
+   on program exit.  Keep an active set of pointers to memory we allocate and
+   pass to putenv, one per environment key.  At program exit remove any
+   environment values that may still reference memory we allocated.  Then free
+   the memory.  This will not affect any environment values we never set.  */
+
+#ifdef __INTEL_COMPILER
+#pragma warning disable 444 /* base has non-virtual destructor */
+#endif
+
+class kwsysEnv : public kwsysEnvSet
+{
+public:
+  ~kwsysEnv()
+  {
+    for (iterator i = this->begin(); i != this->end(); ++i) {
+#if defined(_WIN32)
+      const std::string s = Encoding::ToNarrow(*i);
+      kwsysUnPutEnv(s.c_str());
+#else
+      kwsysUnPutEnv(*i);
+#endif
+      free(const_cast<envchar*>(*i));
+    }
+  }
+  bool Put(const char* env)
+  {
+#if defined(_WIN32)
+    const std::wstring wEnv = Encoding::ToWide(env);
+    wchar_t* newEnv = _wcsdup(wEnv.c_str());
+#else
+    char* newEnv = strdup(env);
+#endif
+    Free oldEnv(this->Release(newEnv));
+    this->insert(newEnv);
+#if defined(_WIN32)
+    return _wputenv(newEnv) == 0;
+#else
+    return putenv(newEnv) == 0;
+#endif
+  }
+  bool UnPut(const char* env)
+  {
+#if defined(_WIN32)
+    const std::wstring wEnv = Encoding::ToWide(env);
+    Free oldEnv(this->Release(wEnv.c_str()));
+#else
+    Free oldEnv(this->Release(env));
+#endif
+    return kwsysUnPutEnv(env) == 0;
+  }
+};
+
+static kwsysEnv kwsysEnvInstance;
+
+bool SystemTools::PutEnv(const std::string& env)
+{
+  return kwsysEnvInstance.Put(env.c_str());
+}
+
+bool SystemTools::UnPutEnv(const std::string& env)
+{
+  return kwsysEnvInstance.UnPut(env.c_str());
+}
+
+#endif
+
+//----------------------------------------------------------------------------
+
+const char* SystemTools::GetExecutableExtension()
+{
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS)
+  return ".exe";
+#else
+  return "";
+#endif
+}
+
+FILE* SystemTools::Fopen(const std::string& file, const char* mode)
+{
+#ifdef _WIN32
+  return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(),
+                 Encoding::ToWide(mode).c_str());
+#else
+  return fopen(file.c_str(), mode);
+#endif
+}
+
+bool SystemTools::MakeDirectory(const char* path)
+{
+  if (!path) {
+    return false;
+  }
+  return SystemTools::MakeDirectory(std::string(path));
+}
+
+bool SystemTools::MakeDirectory(const std::string& path)
+{
+  if (SystemTools::PathExists(path)) {
+    return SystemTools::FileIsDirectory(path);
+  }
+  if (path.empty()) {
+    return false;
+  }
+  std::string dir = path;
+  SystemTools::ConvertToUnixSlashes(dir);
+
+  std::string::size_type pos = 0;
+  std::string topdir;
+  while ((pos = dir.find('/', pos)) != std::string::npos) {
+    topdir = dir.substr(0, pos);
+    Mkdir(topdir);
+    pos++;
+  }
+  topdir = dir;
+  if (Mkdir(topdir) != 0) {
+    // There is a bug in the Borland Run time library which makes MKDIR
+    // return EACCES when it should return EEXISTS
+    // if it is some other error besides directory exists
+    // then return false
+    if ((errno != EEXIST)
+#ifdef __BORLANDC__
+        && (errno != EACCES)
+#endif
+          ) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// replace replace with with as many times as it shows up in source.
+// write the result into source.
+void SystemTools::ReplaceString(std::string& source,
+                                const std::string& replace,
+                                const std::string& with)
+{
+  // do while hangs if replaceSize is 0
+  if (replace.empty()) {
+    return;
+  }
+
+  SystemTools::ReplaceString(source, replace.c_str(), replace.size(), with);
+}
+
+void SystemTools::ReplaceString(std::string& source, const char* replace,
+                                const char* with)
+{
+  // do while hangs if replaceSize is 0
+  if (!*replace) {
+    return;
+  }
+
+  SystemTools::ReplaceString(source, replace, strlen(replace),
+                             with ? with : "");
+}
+
+void SystemTools::ReplaceString(std::string& source, const char* replace,
+                                size_t replaceSize, const std::string& with)
+{
+  const char* src = source.c_str();
+  char* searchPos = const_cast<char*>(strstr(src, replace));
+
+  // get out quick if string is not found
+  if (!searchPos) {
+    return;
+  }
+
+  // perform replacements until done
+  char* orig = strdup(src);
+  char* currentPos = orig;
+  searchPos = searchPos - src + orig;
+
+  // initialize the result
+  source.erase(source.begin(), source.end());
+  do {
+    *searchPos = '\0';
+    source += currentPos;
+    currentPos = searchPos + replaceSize;
+    // replace
+    source += with;
+    searchPos = strstr(currentPos, replace);
+  } while (searchPos);
+
+  // copy any trailing text
+  source += currentPos;
+  free(orig);
+}
+
+#if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY)
+#define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY
+#define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY
+#else
+#define KWSYS_ST_KEY_WOW64_32KEY 0x0200
+#define KWSYS_ST_KEY_WOW64_64KEY 0x0100
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static bool SystemToolsParseRegistryKey(const std::string& key,
+                                        HKEY& primaryKey, std::string& second,
+                                        std::string& valuename)
+{
+  std::string primary = key;
+
+  size_t start = primary.find('\\');
+  if (start == std::string::npos) {
+    return false;
+  }
+
+  size_t valuenamepos = primary.find(';');
+  if (valuenamepos != std::string::npos) {
+    valuename = primary.substr(valuenamepos + 1);
+  }
+
+  second = primary.substr(start + 1, valuenamepos - start - 1);
+  primary = primary.substr(0, start);
+
+  if (primary == "HKEY_CURRENT_USER") {
+    primaryKey = HKEY_CURRENT_USER;
+  }
+  if (primary == "HKEY_CURRENT_CONFIG") {
+    primaryKey = HKEY_CURRENT_CONFIG;
+  }
+  if (primary == "HKEY_CLASSES_ROOT") {
+    primaryKey = HKEY_CLASSES_ROOT;
+  }
+  if (primary == "HKEY_LOCAL_MACHINE") {
+    primaryKey = HKEY_LOCAL_MACHINE;
+  }
+  if (primary == "HKEY_USERS") {
+    primaryKey = HKEY_USERS;
+  }
+
+  return true;
+}
+
+static DWORD SystemToolsMakeRegistryMode(DWORD mode,
+                                         SystemTools::KeyWOW64 view)
+{
+  // only add the modes when on a system that supports Wow64.
+  static FARPROC wow64p =
+    GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process");
+  if (wow64p == NULL) {
+    return mode;
+  }
+
+  if (view == SystemTools::KeyWOW64_32) {
+    return mode | KWSYS_ST_KEY_WOW64_32KEY;
+  } else if (view == SystemTools::KeyWOW64_64) {
+    return mode | KWSYS_ST_KEY_WOW64_64KEY;
+  }
+  return mode;
+}
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::GetRegistrySubKeys(const std::string& key,
+                                     std::vector<std::string>& subkeys,
+                                     KeyWOW64 view)
+{
+  HKEY primaryKey = HKEY_CURRENT_USER;
+  std::string second;
+  std::string valuename;
+  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
+    return false;
+  }
+
+  HKEY hKey;
+  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
+                    SystemToolsMakeRegistryMode(KEY_READ, view),
+                    &hKey) != ERROR_SUCCESS) {
+    return false;
+  } else {
+    wchar_t name[1024];
+    DWORD dwNameSize = sizeof(name) / sizeof(name[0]);
+
+    DWORD i = 0;
+    while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS) {
+      subkeys.push_back(Encoding::ToNarrow(name));
+      ++i;
+    }
+
+    RegCloseKey(hKey);
+  }
+
+  return true;
+}
+#else
+bool SystemTools::GetRegistrySubKeys(const std::string&,
+                                     std::vector<std::string>&, KeyWOW64)
+{
+  return false;
+}
+#endif
+
+// Read a registry value.
+// Example :
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+//      =>  will return the data of the "default" value of the key
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+//      =>  will return the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value,
+                                    KeyWOW64 view)
+{
+  bool valueset = false;
+  HKEY primaryKey = HKEY_CURRENT_USER;
+  std::string second;
+  std::string valuename;
+  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
+    return false;
+  }
+
+  HKEY hKey;
+  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
+                    SystemToolsMakeRegistryMode(KEY_READ, view),
+                    &hKey) != ERROR_SUCCESS) {
+    return false;
+  } else {
+    DWORD dwType, dwSize;
+    dwSize = 1023;
+    wchar_t data[1024];
+    if (RegQueryValueExW(hKey, Encoding::ToWide(valuename).c_str(), NULL,
+                         &dwType, (BYTE*)data, &dwSize) == ERROR_SUCCESS) {
+      if (dwType == REG_SZ) {
+        value = Encoding::ToNarrow(data);
+        valueset = true;
+      } else if (dwType == REG_EXPAND_SZ) {
+        wchar_t expanded[1024];
+        DWORD dwExpandedSize = sizeof(expanded) / sizeof(expanded[0]);
+        if (ExpandEnvironmentStringsW(data, expanded, dwExpandedSize)) {
+          value = Encoding::ToNarrow(expanded);
+          valueset = true;
+        }
+      }
+    }
+
+    RegCloseKey(hKey);
+  }
+
+  return valueset;
+}
+#else
+bool SystemTools::ReadRegistryValue(const std::string&, std::string&, KeyWOW64)
+{
+  return false;
+}
+#endif
+
+// Write a registry value.
+// Example :
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+//      =>  will set the data of the "default" value of the key
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+//      =>  will set the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::WriteRegistryValue(const std::string& key,
+                                     const std::string& value, KeyWOW64 view)
+{
+  HKEY primaryKey = HKEY_CURRENT_USER;
+  std::string second;
+  std::string valuename;
+  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
+    return false;
+  }
+
+  HKEY hKey;
+  DWORD dwDummy;
+  wchar_t lpClass[] = L"";
+  if (RegCreateKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, lpClass,
+                      REG_OPTION_NON_VOLATILE,
+                      SystemToolsMakeRegistryMode(KEY_WRITE, view), NULL,
+                      &hKey, &dwDummy) != ERROR_SUCCESS) {
+    return false;
+  }
+
+  std::wstring wvalue = Encoding::ToWide(value);
+  if (RegSetValueExW(hKey, Encoding::ToWide(valuename).c_str(), 0, REG_SZ,
+                     (CONST BYTE*)wvalue.c_str(),
+                     (DWORD)(sizeof(wchar_t) * (wvalue.size() + 1))) ==
+      ERROR_SUCCESS) {
+    return true;
+  }
+  return false;
+}
+#else
+bool SystemTools::WriteRegistryValue(const std::string&, const std::string&,
+                                     KeyWOW64)
+{
+  return false;
+}
+#endif
+
+// Delete a registry value.
+// Example :
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+//      =>  will delete the data of the "default" value of the key
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+//      =>  will delete  the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view)
+{
+  HKEY primaryKey = HKEY_CURRENT_USER;
+  std::string second;
+  std::string valuename;
+  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
+    return false;
+  }
+
+  HKEY hKey;
+  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
+                    SystemToolsMakeRegistryMode(KEY_WRITE, view),
+                    &hKey) != ERROR_SUCCESS) {
+    return false;
+  } else {
+    if (RegDeleteValue(hKey, (LPTSTR)valuename.c_str()) == ERROR_SUCCESS) {
+      RegCloseKey(hKey);
+      return true;
+    }
+  }
+  return false;
+}
+#else
+bool SystemTools::DeleteRegistryValue(const std::string&, KeyWOW64)
+{
+  return false;
+}
+#endif
+
+bool SystemTools::SameFile(const std::string& file1, const std::string& file2)
+{
+#ifdef _WIN32
+  HANDLE hFile1, hFile2;
+
+  hFile1 =
+    CreateFileW(Encoding::ToWide(file1).c_str(), GENERIC_READ, FILE_SHARE_READ,
+                NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  hFile2 =
+    CreateFileW(Encoding::ToWide(file2).c_str(), GENERIC_READ, FILE_SHARE_READ,
+                NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if (hFile1 == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE) {
+    if (hFile1 != INVALID_HANDLE_VALUE) {
+      CloseHandle(hFile1);
+    }
+    if (hFile2 != INVALID_HANDLE_VALUE) {
+      CloseHandle(hFile2);
+    }
+    return false;
+  }
+
+  BY_HANDLE_FILE_INFORMATION fiBuf1;
+  BY_HANDLE_FILE_INFORMATION fiBuf2;
+  GetFileInformationByHandle(hFile1, &fiBuf1);
+  GetFileInformationByHandle(hFile2, &fiBuf2);
+  CloseHandle(hFile1);
+  CloseHandle(hFile2);
+  return (fiBuf1.dwVolumeSerialNumber == fiBuf2.dwVolumeSerialNumber &&
+          fiBuf1.nFileIndexHigh == fiBuf2.nFileIndexHigh &&
+          fiBuf1.nFileIndexLow == fiBuf2.nFileIndexLow);
+#else
+  struct stat fileStat1, fileStat2;
+  if (stat(file1.c_str(), &fileStat1) == 0 &&
+      stat(file2.c_str(), &fileStat2) == 0) {
+    // see if the files are the same file
+    // check the device inode and size
+    if (memcmp(&fileStat2.st_dev, &fileStat1.st_dev,
+               sizeof(fileStat1.st_dev)) == 0 &&
+        memcmp(&fileStat2.st_ino, &fileStat1.st_ino,
+               sizeof(fileStat1.st_ino)) == 0 &&
+        fileStat2.st_size == fileStat1.st_size) {
+      return true;
+    }
+  }
+  return false;
+#endif
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::PathExists(const std::string& path)
+{
+  if (path.empty()) {
+    return false;
+  }
+#if defined(__CYGWIN__)
+  // Convert path to native windows path if possible.
+  char winpath[MAX_PATH];
+  if (SystemTools::PathCygwinToWin32(path.c_str(), winpath)) {
+    return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES);
+  }
+  struct stat st;
+  return lstat(path.c_str(), &st) == 0;
+#elif defined(_WIN32)
+  return (GetFileAttributesW(Encoding::ToWindowsExtendedPath(path).c_str()) !=
+          INVALID_FILE_ATTRIBUTES);
+#else
+  struct stat st;
+  return lstat(path.c_str(), &st) == 0;
+#endif
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const char* filename)
+{
+  if (!filename) {
+    return false;
+  }
+  return SystemTools::FileExists(std::string(filename));
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const std::string& filename)
+{
+  if (filename.empty()) {
+    return false;
+  }
+#if defined(__CYGWIN__)
+  // Convert filename to native windows path if possible.
+  char winpath[MAX_PATH];
+  if (SystemTools::PathCygwinToWin32(filename.c_str(), winpath)) {
+    return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES);
+  }
+  return access(filename.c_str(), R_OK) == 0;
+#elif defined(_WIN32)
+  return (
+    GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str()) !=
+    INVALID_FILE_ATTRIBUTES);
+#else
+// SCO OpenServer 5.0.7/3.2's command has 711 permission.
+#if defined(_SCO_DS)
+  return access(filename.c_str(), F_OK) == 0;
+#else
+  return access(filename.c_str(), R_OK) == 0;
+#endif
+#endif
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const char* filename, bool isFile)
+{
+  if (!filename) {
+    return false;
+  }
+  return SystemTools::FileExists(std::string(filename), isFile);
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const std::string& filename, bool isFile)
+{
+  if (SystemTools::FileExists(filename)) {
+    // If isFile is set return not FileIsDirectory,
+    // so this will only be true if it is a file
+    return !isFile || !SystemTools::FileIsDirectory(filename);
+  }
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::TestFileAccess(const char* filename,
+                                 TestFilePermissions permissions)
+{
+  if (!filename) {
+    return false;
+  }
+  return SystemTools::TestFileAccess(std::string(filename), permissions);
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::TestFileAccess(const std::string& filename,
+                                 TestFilePermissions permissions)
+{
+  if (filename.empty()) {
+    return false;
+  }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // If execute set, change to read permission (all files on Windows
+  // are executable if they are readable).  The CRT will always fail
+  // if you pass an execute bit.
+  if (permissions & TEST_FILE_EXECUTE) {
+    permissions &= ~TEST_FILE_EXECUTE;
+    permissions |= TEST_FILE_READ;
+  }
+  return _waccess(Encoding::ToWindowsExtendedPath(filename).c_str(),
+                  permissions) == 0;
+#else
+  return access(filename.c_str(), permissions) == 0;
+#endif
+}
+
+//----------------------------------------------------------------------------
+int SystemTools::Stat(const char* path, SystemTools::Stat_t* buf)
+{
+  if (!path) {
+    errno = EFAULT;
+    return -1;
+  }
+  return SystemTools::Stat(std::string(path), buf);
+}
+
+//----------------------------------------------------------------------------
+int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf)
+{
+  if (path.empty()) {
+    errno = ENOENT;
+    return -1;
+  }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // Ideally we should use Encoding::ToWindowsExtendedPath to support
+  // long paths, but _wstat64 rejects paths with '?' in them, thinking
+  // they are wildcards.
+  std::wstring const& wpath = Encoding::ToWide(path);
+#if defined(__BORLANDC__)
+  return _wstati64(wpath.c_str(), buf);
+#else
+  return _wstat64(wpath.c_str(), buf);
+#endif
+#else
+  return stat(path.c_str(), buf);
+#endif
+}
+
+//----------------------------------------------------------------------------
+#ifdef __CYGWIN__
+bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path)
+{
+  SystemToolsTranslationMap::iterator i =
+    SystemTools::Cyg2Win32Map->find(path);
+
+  if (i != SystemTools::Cyg2Win32Map->end()) {
+    strncpy(win32_path, i->second.c_str(), MAX_PATH);
+  } else {
+    if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) !=
+        0) {
+      win32_path[0] = 0;
+    }
+    SystemToolsTranslationMap::value_type entry(path, win32_path);
+    SystemTools::Cyg2Win32Map->insert(entry);
+  }
+  return win32_path[0] != 0;
+}
+#endif
+
+bool SystemTools::Touch(const std::string& filename, bool create)
+{
+  if (!SystemTools::PathExists(filename)) {
+    if (create) {
+      FILE* file = Fopen(filename, "a+b");
+      if (file) {
+        fclose(file);
+        return true;
+      }
+      return false;
+    } else {
+      return true;
+    }
+  }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  HANDLE h = CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(),
+                         FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0,
+                         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+  if (!h) {
+    return false;
+  }
+  FILETIME mtime;
+  GetSystemTimeAsFileTime(&mtime);
+  if (!SetFileTime(h, 0, 0, &mtime)) {
+    CloseHandle(h);
+    return false;
+  }
+  CloseHandle(h);
+#elif KWSYS_CXX_HAS_UTIMENSAT
+  struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, UTIME_NOW } };
+  if (utimensat(AT_FDCWD, filename.c_str(), times, 0) < 0) {
+    return false;
+  }
+#else
+  struct stat st;
+  if (stat(filename.c_str(), &st) < 0) {
+    return false;
+  }
+  struct timeval mtime;
+  gettimeofday(&mtime, 0);
+#if KWSYS_CXX_HAS_UTIMES
+  struct timeval atime;
+#if KWSYS_CXX_STAT_HAS_ST_MTIM
+  atime.tv_sec = st.st_atim.tv_sec;
+  atime.tv_usec = st.st_atim.tv_nsec / 1000;
+#elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+  atime.tv_sec = st.st_atimespec.tv_sec;
+  atime.tv_usec = st.st_atimespec.tv_nsec / 1000;
+#else
+  atime.tv_sec = st.st_atime;
+  atime.tv_usec = 0;
+#endif
+  struct timeval times[2] = { atime, mtime };
+  if (utimes(filename.c_str(), times) < 0) {
+    return false;
+  }
+#else
+  struct utimbuf times = { st.st_atime, mtime.tv_sec };
+  if (utime(filename.c_str(), &times) < 0) {
+    return false;
+  }
+#endif
+#endif
+  return true;
+}
+
+bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2,
+                                  int* result)
+{
+  // Default to same time.
+  *result = 0;
+#if !defined(_WIN32) || defined(__CYGWIN__)
+  // POSIX version.  Use stat function to get file modification time.
+  struct stat s1;
+  if (stat(f1.c_str(), &s1) != 0) {
+    return false;
+  }
+  struct stat s2;
+  if (stat(f2.c_str(), &s2) != 0) {
+    return false;
+  }
+#if KWSYS_CXX_STAT_HAS_ST_MTIM
+  // Compare using nanosecond resolution.
+  if (s1.st_mtim.tv_sec < s2.st_mtim.tv_sec) {
+    *result = -1;
+  } else if (s1.st_mtim.tv_sec > s2.st_mtim.tv_sec) {
+    *result = 1;
+  } else if (s1.st_mtim.tv_nsec < s2.st_mtim.tv_nsec) {
+    *result = -1;
+  } else if (s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec) {
+    *result = 1;
+  }
+#elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+  // Compare using nanosecond resolution.
+  if (s1.st_mtimespec.tv_sec < s2.st_mtimespec.tv_sec) {
+    *result = -1;
+  } else if (s1.st_mtimespec.tv_sec > s2.st_mtimespec.tv_sec) {
+    *result = 1;
+  } else if (s1.st_mtimespec.tv_nsec < s2.st_mtimespec.tv_nsec) {
+    *result = -1;
+  } else if (s1.st_mtimespec.tv_nsec > s2.st_mtimespec.tv_nsec) {
+    *result = 1;
+  }
+#else
+  // Compare using 1 second resolution.
+  if (s1.st_mtime < s2.st_mtime) {
+    *result = -1;
+  } else if (s1.st_mtime > s2.st_mtime) {
+    *result = 1;
+  }
+#endif
+#else
+  // Windows version.  Get the modification time from extended file attributes.
+  WIN32_FILE_ATTRIBUTE_DATA f1d;
+  WIN32_FILE_ATTRIBUTE_DATA f2d;
+  if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f1).c_str(),
+                            GetFileExInfoStandard, &f1d)) {
+    return false;
+  }
+  if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f2).c_str(),
+                            GetFileExInfoStandard, &f2d)) {
+    return false;
+  }
+
+  // Compare the file times using resolution provided by system call.
+  *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime);
+#endif
+  return true;
+}
+
+// Return a capitalized string (i.e the first letter is uppercased, all other
+// are lowercased)
+std::string SystemTools::Capitalized(const std::string& s)
+{
+  std::string n;
+  if (s.empty()) {
+    return n;
+  }
+  n.resize(s.size());
+  n[0] = static_cast<std::string::value_type>(toupper(s[0]));
+  for (size_t i = 1; i < s.size(); i++) {
+    n[i] = static_cast<std::string::value_type>(tolower(s[i]));
+  }
+  return n;
+}
+
+// Return capitalized words
+std::string SystemTools::CapitalizedWords(const std::string& s)
+{
+  std::string n(s);
+  for (size_t i = 0; i < s.size(); i++) {
+#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG)
+    // MS has an assert that will fail if s[i] < 0; setting
+    // LC_CTYPE using setlocale() does *not* help. Painful.
+    if ((int)s[i] >= 0 && isalpha(s[i]) &&
+        (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1]))))
+#else
+    if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1])))
+#endif
+    {
+      n[i] = static_cast<std::string::value_type>(toupper(s[i]));
+    }
+  }
+  return n;
+}
+
+// Return uncapitalized words
+std::string SystemTools::UnCapitalizedWords(const std::string& s)
+{
+  std::string n(s);
+  for (size_t i = 0; i < s.size(); i++) {
+#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG)
+    // MS has an assert that will fail if s[i] < 0; setting
+    // LC_CTYPE using setlocale() does *not* help. Painful.
+    if ((int)s[i] >= 0 && isalpha(s[i]) &&
+        (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1]))))
+#else
+    if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1])))
+#endif
+    {
+      n[i] = static_cast<std::string::value_type>(tolower(s[i]));
+    }
+  }
+  return n;
+}
+
+// only works for words with at least two letters
+std::string SystemTools::AddSpaceBetweenCapitalizedWords(const std::string& s)
+{
+  std::string n;
+  if (!s.empty()) {
+    n.reserve(s.size());
+    n += s[0];
+    for (size_t i = 1; i < s.size(); i++) {
+      if (isupper(s[i]) && !isspace(s[i - 1]) && !isupper(s[i - 1])) {
+        n += ' ';
+      }
+      n += s[i];
+    }
+  }
+  return n;
+}
+
+char* SystemTools::AppendStrings(const char* str1, const char* str2)
+{
+  if (!str1) {
+    return SystemTools::DuplicateString(str2);
+  }
+  if (!str2) {
+    return SystemTools::DuplicateString(str1);
+  }
+  size_t len1 = strlen(str1);
+  char* newstr = new char[len1 + strlen(str2) + 1];
+  if (!newstr) {
+    return 0;
+  }
+  strcpy(newstr, str1);
+  strcat(newstr + len1, str2);
+  return newstr;
+}
+
+char* SystemTools::AppendStrings(const char* str1, const char* str2,
+                                 const char* str3)
+{
+  if (!str1) {
+    return SystemTools::AppendStrings(str2, str3);
+  }
+  if (!str2) {
+    return SystemTools::AppendStrings(str1, str3);
+  }
+  if (!str3) {
+    return SystemTools::AppendStrings(str1, str2);
+  }
+
+  size_t len1 = strlen(str1), len2 = strlen(str2);
+  char* newstr = new char[len1 + len2 + strlen(str3) + 1];
+  if (!newstr) {
+    return 0;
+  }
+  strcpy(newstr, str1);
+  strcat(newstr + len1, str2);
+  strcat(newstr + len1 + len2, str3);
+  return newstr;
+}
+
+// Return a lower case string
+std::string SystemTools::LowerCase(const std::string& s)
+{
+  std::string n;
+  n.resize(s.size());
+  for (size_t i = 0; i < s.size(); i++) {
+    n[i] = static_cast<std::string::value_type>(tolower(s[i]));
+  }
+  return n;
+}
+
+// Return a lower case string
+std::string SystemTools::UpperCase(const std::string& s)
+{
+  std::string n;
+  n.resize(s.size());
+  for (size_t i = 0; i < s.size(); i++) {
+    n[i] = static_cast<std::string::value_type>(toupper(s[i]));
+  }
+  return n;
+}
+
+// Count char in string
+size_t SystemTools::CountChar(const char* str, char c)
+{
+  size_t count = 0;
+
+  if (str) {
+    while (*str) {
+      if (*str == c) {
+        ++count;
+      }
+      ++str;
+    }
+  }
+  return count;
+}
+
+// Remove chars in string
+char* SystemTools::RemoveChars(const char* str, const char* toremove)
+{
+  if (!str) {
+    return NULL;
+  }
+  char* clean_str = new char[strlen(str) + 1];
+  char* ptr = clean_str;
+  while (*str) {
+    const char* str2 = toremove;
+    while (*str2 && *str != *str2) {
+      ++str2;
+    }
+    if (!*str2) {
+      *ptr++ = *str;
+    }
+    ++str;
+  }
+  *ptr = '\0';
+  return clean_str;
+}
+
+// Remove chars in string
+char* SystemTools::RemoveCharsButUpperHex(const char* str)
+{
+  if (!str) {
+    return 0;
+  }
+  char* clean_str = new char[strlen(str) + 1];
+  char* ptr = clean_str;
+  while (*str) {
+    if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'F')) {
+      *ptr++ = *str;
+    }
+    ++str;
+  }
+  *ptr = '\0';
+  return clean_str;
+}
+
+// Replace chars in string
+char* SystemTools::ReplaceChars(char* str, const char* toreplace,
+                                char replacement)
+{
+  if (str) {
+    char* ptr = str;
+    while (*ptr) {
+      const char* ptr2 = toreplace;
+      while (*ptr2) {
+        if (*ptr == *ptr2) {
+          *ptr = replacement;
+        }
+        ++ptr2;
+      }
+      ++ptr;
+    }
+  }
+  return str;
+}
+
+// Returns if string starts with another string
+bool SystemTools::StringStartsWith(const char* str1, const char* str2)
+{
+  if (!str1 || !str2) {
+    return false;
+  }
+  size_t len1 = strlen(str1), len2 = strlen(str2);
+  return len1 >= len2 && !strncmp(str1, str2, len2) ? true : false;
+}
+
+// Returns if string starts with another string
+bool SystemTools::StringStartsWith(const std::string& str1, const char* str2)
+{
+  if (!str2) {
+    return false;
+  }
+  size_t len1 = str1.size(), len2 = strlen(str2);
+  return len1 >= len2 && !strncmp(str1.c_str(), str2, len2) ? true : false;
+}
+
+// Returns if string ends with another string
+bool SystemTools::StringEndsWith(const char* str1, const char* str2)
+{
+  if (!str1 || !str2) {
+    return false;
+  }
+  size_t len1 = strlen(str1), len2 = strlen(str2);
+  return len1 >= len2 && !strncmp(str1 + (len1 - len2), str2, len2) ? true
+                                                                    : false;
+}
+
+// Returns if string ends with another string
+bool SystemTools::StringEndsWith(const std::string& str1, const char* str2)
+{
+  if (!str2) {
+    return false;
+  }
+  size_t len1 = str1.size(), len2 = strlen(str2);
+  return len1 >= len2 && !strncmp(str1.c_str() + (len1 - len2), str2, len2)
+    ? true
+    : false;
+}
+
+// Returns a pointer to the last occurence of str2 in str1
+const char* SystemTools::FindLastString(const char* str1, const char* str2)
+{
+  if (!str1 || !str2) {
+    return NULL;
+  }
+
+  size_t len1 = strlen(str1), len2 = strlen(str2);
+  if (len1 >= len2) {
+    const char* ptr = str1 + len1 - len2;
+    do {
+      if (!strncmp(ptr, str2, len2)) {
+        return ptr;
+      }
+    } while (ptr-- != str1);
+  }
+
+  return NULL;
+}
+
+// Duplicate string
+char* SystemTools::DuplicateString(const char* str)
+{
+  if (str) {
+    char* newstr = new char[strlen(str) + 1];
+    return strcpy(newstr, str);
+  }
+  return NULL;
+}
+
+// Return a cropped string
+std::string SystemTools::CropString(const std::string& s, size_t max_len)
+{
+  if (!s.size() || max_len == 0 || max_len >= s.size()) {
+    return s;
+  }
+
+  std::string n;
+  n.reserve(max_len);
+
+  size_t middle = max_len / 2;
+
+  n += s.substr(0, middle);
+  n += s.substr(s.size() - (max_len - middle), std::string::npos);
+
+  if (max_len > 2) {
+    n[middle] = '.';
+    if (max_len > 3) {
+      n[middle - 1] = '.';
+      if (max_len > 4) {
+        n[middle + 1] = '.';
+      }
+    }
+  }
+
+  return n;
+}
+
+//----------------------------------------------------------------------------
+std::vector<kwsys::String> SystemTools::SplitString(const std::string& p,
+                                                    char sep, bool isPath)
+{
+  std::string path = p;
+  std::vector<kwsys::String> paths;
+  if (path.empty()) {
+    return paths;
+  }
+  if (isPath && path[0] == '/') {
+    path.erase(path.begin());
+    paths.push_back("/");
+  }
+  std::string::size_type pos1 = 0;
+  std::string::size_type pos2 = path.find(sep, pos1 + 1);
+  while (pos2 != std::string::npos) {
+    paths.push_back(path.substr(pos1, pos2 - pos1));
+    pos1 = pos2 + 1;
+    pos2 = path.find(sep, pos1 + 1);
+  }
+  paths.push_back(path.substr(pos1, pos2 - pos1));
+
+  return paths;
+}
+
+//----------------------------------------------------------------------------
+int SystemTools::EstimateFormatLength(const char* format, va_list ap)
+{
+  if (!format) {
+    return 0;
+  }
+
+  // Quick-hack attempt at estimating the length of the string.
+  // Should never under-estimate.
+
+  // Start with the length of the format string itself.
+
+  size_t length = strlen(format);
+
+  // Increase the length for every argument in the format.
+
+  const char* cur = format;
+  while (*cur) {
+    if (*cur++ == '%') {
+      // Skip "%%" since it doesn't correspond to a va_arg.
+      if (*cur != '%') {
+        while (!int(isalpha(*cur))) {
+          ++cur;
+        }
+        switch (*cur) {
+          case 's': {
+            // Check the length of the string.
+            char* s = va_arg(ap, char*);
+            if (s) {
+              length += strlen(s);
+            }
+          } break;
+          case 'e':
+          case 'f':
+          case 'g': {
+            // Assume the argument contributes no more than 64 characters.
+            length += 64;
+
+            // Eat the argument.
+            static_cast<void>(va_arg(ap, double));
+          } break;
+          default: {
+            // Assume the argument contributes no more than 64 characters.
+            length += 64;
+
+            // Eat the argument.
+            static_cast<void>(va_arg(ap, int));
+          } break;
+        }
+      }
+
+      // Move past the characters just tested.
+      ++cur;
+    }
+  }
+
+  return static_cast<int>(length);
+}
+
+std::string SystemTools::EscapeChars(const char* str,
+                                     const char* chars_to_escape,
+                                     char escape_char)
+{
+  std::string n;
+  if (str) {
+    if (!chars_to_escape || !*chars_to_escape) {
+      n.append(str);
+    } else {
+      n.reserve(strlen(str));
+      while (*str) {
+        const char* ptr = chars_to_escape;
+        while (*ptr) {
+          if (*str == *ptr) {
+            n += escape_char;
+            break;
+          }
+          ++ptr;
+        }
+        n += *str;
+        ++str;
+      }
+    }
+  }
+  return n;
+}
+
+#ifdef __VMS
+static void ConvertVMSToUnix(std::string& path)
+{
+  std::string::size_type rootEnd = path.find(":[");
+  std::string::size_type pathEnd = path.find("]");
+  if (rootEnd != path.npos) {
+    std::string root = path.substr(0, rootEnd);
+    std::string pathPart = path.substr(rootEnd + 2, pathEnd - rootEnd - 2);
+    const char* pathCString = pathPart.c_str();
+    const char* pos0 = pathCString;
+    for (std::string::size_type pos = 0; *pos0; ++pos) {
+      if (*pos0 == '.') {
+        pathPart[pos] = '/';
+      }
+      pos0++;
+    }
+    path = "/" + root + "/" + pathPart;
+  }
+}
+#endif
+
+// convert windows slashes to unix slashes
+void SystemTools::ConvertToUnixSlashes(std::string& path)
+{
+  const char* pathCString = path.c_str();
+  bool hasDoubleSlash = false;
+#ifdef __VMS
+  ConvertVMSToUnix(path);
+#else
+  const char* pos0 = pathCString;
+  const char* pos1 = pathCString + 1;
+  for (std::string::size_type pos = 0; *pos0; ++pos) {
+    // make sure we don't convert an escaped space to a unix slash
+    if (*pos0 == '\\' && *pos1 != ' ') {
+      path[pos] = '/';
+    }
+
+    // Also, reuse the loop to check for slash followed by another slash
+    if (*pos1 == '/' && *(pos1 + 1) == '/' && !hasDoubleSlash) {
+#ifdef _WIN32
+      // However, on windows if the first characters are both slashes,
+      // then keep them that way, so that network paths can be handled.
+      if (pos > 0) {
+        hasDoubleSlash = true;
+      }
+#else
+      hasDoubleSlash = true;
+#endif
+    }
+
+    pos0++;
+    pos1++;
+  }
+
+  if (hasDoubleSlash) {
+    SystemTools::ReplaceString(path, "//", "/");
+  }
+#endif
+  // remove any trailing slash
+  if (!path.empty()) {
+    // if there is a tilda ~ then replace it with HOME
+    pathCString = path.c_str();
+    if (pathCString[0] == '~' &&
+        (pathCString[1] == '/' || pathCString[1] == '\0')) {
+      std::string homeEnv;
+      if (SystemTools::GetEnv("HOME", homeEnv)) {
+        path.replace(0, 1, homeEnv);
+      }
+    }
+#ifdef HAVE_GETPWNAM
+    else if (pathCString[0] == '~') {
+      std::string::size_type idx = path.find_first_of("/\0");
+      std::string user = path.substr(1, idx - 1);
+      passwd* pw = getpwnam(user.c_str());
+      if (pw) {
+        path.replace(0, idx, pw->pw_dir);
+      }
+    }
+#endif
+    // remove trailing slash if the path is more than
+    // a single /
+    pathCString = path.c_str();
+    size_t size = path.size();
+    if (size > 1 && *path.rbegin() == '/') {
+      // if it is c:/ then do not remove the trailing slash
+      if (!((size == 3 && pathCString[1] == ':'))) {
+        path.resize(size - 1);
+      }
+    }
+  }
+}
+
+#ifdef _WIN32
+std::wstring SystemTools::ConvertToWindowsExtendedPath(
+  const std::string& source)
+{
+  return Encoding::ToWindowsExtendedPath(source);
+}
+#endif
+
+// change // to /, and escape any spaces in the path
+std::string SystemTools::ConvertToUnixOutputPath(const std::string& path)
+{
+  std::string ret = path;
+
+  // remove // except at the beginning might be a cygwin drive
+  std::string::size_type pos = 1;
+  while ((pos = ret.find("//", pos)) != std::string::npos) {
+    ret.erase(pos, 1);
+  }
+  // escape spaces and () in the path
+  if (ret.find_first_of(" ") != std::string::npos) {
+    std::string result = "";
+    char lastch = 1;
+    for (const char* ch = ret.c_str(); *ch != '\0'; ++ch) {
+      // if it is already escaped then don't try to escape it again
+      if ((*ch == ' ') && lastch != '\\') {
+        result += '\\';
+      }
+      result += *ch;
+      lastch = *ch;
+    }
+    ret = result;
+  }
+  return ret;
+}
+
+std::string SystemTools::ConvertToOutputPath(const std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  return SystemTools::ConvertToWindowsOutputPath(path);
+#else
+  return SystemTools::ConvertToUnixOutputPath(path);
+#endif
+}
+
+// remove double slashes not at the start
+std::string SystemTools::ConvertToWindowsOutputPath(const std::string& path)
+{
+  std::string ret;
+  // make it big enough for all of path and double quotes
+  ret.reserve(path.size() + 3);
+  // put path into the string
+  ret = path;
+  std::string::size_type pos = 0;
+  // first convert all of the slashes
+  while ((pos = ret.find('/', pos)) != std::string::npos) {
+    ret[pos] = '\\';
+    pos++;
+  }
+  // check for really small paths
+  if (ret.size() < 2) {
+    return ret;
+  }
+  // now clean up a bit and remove double slashes
+  // Only if it is not the first position in the path which is a network
+  // path on windows
+  pos = 1; // start at position 1
+  if (ret[0] == '\"') {
+    pos = 2; // if the string is already quoted then start at 2
+    if (ret.size() < 3) {
+      return ret;
+    }
+  }
+  while ((pos = ret.find("\\\\", pos)) != std::string::npos) {
+    ret.erase(pos, 1);
+  }
+  // now double quote the path if it has spaces in it
+  // and is not already double quoted
+  if (ret.find(' ') != std::string::npos && ret[0] != '\"') {
+    ret.insert(static_cast<std::string::size_type>(0),
+               static_cast<std::string::size_type>(1), '\"');
+    ret.append(1, '\"');
+  }
+  return ret;
+}
+
+bool SystemTools::CopyFileIfDifferent(const std::string& source,
+                                      const std::string& destination)
+{
+  // special check for a destination that is a directory
+  // FilesDiffer does not handle file to directory compare
+  if (SystemTools::FileIsDirectory(destination)) {
+    std::string new_destination = destination;
+    SystemTools::ConvertToUnixSlashes(new_destination);
+    new_destination += '/';
+    std::string source_name = source;
+    new_destination += SystemTools::GetFilenameName(source_name);
+    if (SystemTools::FilesDiffer(source, new_destination)) {
+      return SystemTools::CopyFileAlways(source, destination);
+    } else {
+      // the files are the same so the copy is done return
+      // true
+      return true;
+    }
+  }
+  // source and destination are files so do a copy if they
+  // are different
+  if (SystemTools::FilesDiffer(source, destination)) {
+    return SystemTools::CopyFileAlways(source, destination);
+  }
+  // at this point the files must be the same so return true
+  return true;
+}
+
+#define KWSYS_ST_BUFFER 4096
+
+bool SystemTools::FilesDiffer(const std::string& source,
+                              const std::string& destination)
+{
+
+#if defined(_WIN32)
+  WIN32_FILE_ATTRIBUTE_DATA statSource;
+  if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(source).c_str(),
+                           GetFileExInfoStandard, &statSource) == 0) {
+    return true;
+  }
+
+  WIN32_FILE_ATTRIBUTE_DATA statDestination;
+  if (GetFileAttributesExW(
+        Encoding::ToWindowsExtendedPath(destination).c_str(),
+        GetFileExInfoStandard, &statDestination) == 0) {
+    return true;
+  }
+
+  if (statSource.nFileSizeHigh != statDestination.nFileSizeHigh ||
+      statSource.nFileSizeLow != statDestination.nFileSizeLow) {
+    return true;
+  }
+
+  if (statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0) {
+    return false;
+  }
+  off_t nleft =
+    ((__int64)statSource.nFileSizeHigh << 32) + statSource.nFileSizeLow;
+
+#else
+
+  struct stat statSource;
+  if (stat(source.c_str(), &statSource) != 0) {
+    return true;
+  }
+
+  struct stat statDestination;
+  if (stat(destination.c_str(), &statDestination) != 0) {
+    return true;
+  }
+
+  if (statSource.st_size != statDestination.st_size) {
+    return true;
+  }
+
+  if (statSource.st_size == 0) {
+    return false;
+  }
+  off_t nleft = statSource.st_size;
+#endif
+
+#if defined(_WIN32)
+  kwsys::ifstream finSource(source.c_str(), (std::ios::binary | std::ios::in));
+  kwsys::ifstream finDestination(destination.c_str(),
+                                 (std::ios::binary | std::ios::in));
+#else
+  kwsys::ifstream finSource(source.c_str());
+  kwsys::ifstream finDestination(destination.c_str());
+#endif
+  if (!finSource || !finDestination) {
+    return true;
+  }
+
+  // Compare the files a block at a time.
+  char source_buf[KWSYS_ST_BUFFER];
+  char dest_buf[KWSYS_ST_BUFFER];
+  while (nleft > 0) {
+    // Read a block from each file.
+    std::streamsize nnext = (nleft > KWSYS_ST_BUFFER)
+      ? KWSYS_ST_BUFFER
+      : static_cast<std::streamsize>(nleft);
+    finSource.read(source_buf, nnext);
+    finDestination.read(dest_buf, nnext);
+
+    // If either failed to read assume they are different.
+    if (static_cast<std::streamsize>(finSource.gcount()) != nnext ||
+        static_cast<std::streamsize>(finDestination.gcount()) != nnext) {
+      return true;
+    }
+
+    // If this block differs the file differs.
+    if (memcmp(static_cast<const void*>(source_buf),
+               static_cast<const void*>(dest_buf),
+               static_cast<size_t>(nnext)) != 0) {
+      return true;
+    }
+
+    // Update the byte count remaining.
+    nleft -= nnext;
+  }
+
+  // No differences found.
+  return false;
+}
+
+//----------------------------------------------------------------------------
+/**
+ * Copy a file named by "source" to the file named by "destination".
+ */
+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;
+
+  if (SystemTools::FileIsDirectory(source)) {
+    SystemTools::MakeDirectory(destination);
+  } else {
+    const int bufferSize = 4096;
+    char buffer[bufferSize];
+
+    // If destination is a directory, try to create a file with the same
+    // name as the source in that directory.
+
+    std::string destination_dir;
+    if (SystemTools::FileIsDirectory(destination)) {
+      destination_dir = real_destination;
+      SystemTools::ConvertToUnixSlashes(real_destination);
+      real_destination += '/';
+      std::string source_name = source;
+      real_destination += SystemTools::GetFilenameName(source_name);
+    } else {
+      destination_dir = SystemTools::GetFilenamePath(destination);
+    }
+
+    // Create destination directory
+
+    SystemTools::MakeDirectory(destination_dir);
+
+// Open files
+#if defined(_WIN32)
+    kwsys::ifstream fin(
+      Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)).c_str(),
+      std::ios::in | std::ios::binary);
+#else
+    kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary);
+#endif
+    if (!fin) {
+      return false;
+    }
+
+    // try and remove the destination file so that read only destination files
+    // can be written to.
+    // If the remove fails continue so that files in read only directories
+    // that do not allow file removal can be modified.
+    SystemTools::RemoveFile(real_destination);
+
+#if defined(_WIN32)
+    kwsys::ofstream fout(
+      Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(real_destination))
+        .c_str(),
+      std::ios::out | std::ios::trunc | std::ios::binary);
+#else
+    kwsys::ofstream fout(real_destination.c_str(),
+                         std::ios::out | std::ios::trunc | std::ios::binary);
+#endif
+    if (!fout) {
+      return false;
+    }
+
+    // This copy loop is very sensitive on certain platforms with
+    // slightly broken stream libraries (like HPUX).  Normally, it is
+    // incorrect to not check the error condition on the fin.read()
+    // before using the data, but the fin.gcount() will be zero if an
+    // error occurred.  Therefore, the loop should be safe everywhere.
+    while (fin) {
+      fin.read(buffer, bufferSize);
+      if (fin.gcount()) {
+        fout.write(buffer, fin.gcount());
+      } else {
+        break;
+      }
+    }
+
+    // Make sure the operating system has finished writing the file
+    // before closing it.  This will ensure the file is finished before
+    // the check below.
+    fout.flush();
+
+    fin.close();
+    fout.close();
+
+    if (!fout) {
+      return false;
+    }
+  }
+  if (perms) {
+    if (!SystemTools::SetPermissions(real_destination, perm)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::CopyAFile(const std::string& source,
+                            const std::string& destination, bool always)
+{
+  if (always) {
+    return SystemTools::CopyFileAlways(source, destination);
+  } else {
+    return SystemTools::CopyFileIfDifferent(source, destination);
+  }
+}
+
+/**
+ * Copy a directory content from "source" directory to the directory named by
+ * "destination".
+ */
+bool SystemTools::CopyADirectory(const std::string& source,
+                                 const std::string& destination, bool always)
+{
+  Directory dir;
+#ifdef _WIN32
+  dir.Load(Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)));
+#else
+  dir.Load(source);
+#endif
+  size_t fileNum;
+  if (!SystemTools::MakeDirectory(destination)) {
+    return false;
+  }
+  for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
+    if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") &&
+        strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) {
+      std::string fullPath = source;
+      fullPath += "/";
+      fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+      if (SystemTools::FileIsDirectory(fullPath)) {
+        std::string fullDestPath = destination;
+        fullDestPath += "/";
+        fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+        if (!SystemTools::CopyADirectory(fullPath, fullDestPath, always)) {
+          return false;
+        }
+      } else {
+        if (!SystemTools::CopyAFile(fullPath, destination, always)) {
+          return false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+// return size of file; also returns zero if no file exists
+unsigned long SystemTools::FileLength(const std::string& filename)
+{
+  unsigned long length = 0;
+#ifdef _WIN32
+  WIN32_FILE_ATTRIBUTE_DATA fs;
+  if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(),
+                           GetFileExInfoStandard, &fs) != 0) {
+    /* To support the full 64-bit file size, use fs.nFileSizeHigh
+     * and fs.nFileSizeLow to construct the 64 bit size
+
+    length = ((__int64)fs.nFileSizeHigh << 32) + fs.nFileSizeLow;
+     */
+    length = static_cast<unsigned long>(fs.nFileSizeLow);
+  }
+#else
+  struct stat fs;
+  if (stat(filename.c_str(), &fs) == 0) {
+    length = static_cast<unsigned long>(fs.st_size);
+  }
+#endif
+  return length;
+}
+
+int SystemTools::Strucmp(const char* l, const char* r)
+{
+  int lc;
+  int rc;
+  do {
+    lc = tolower(*l++);
+    rc = tolower(*r++);
+  } while (lc == rc && lc);
+  return lc - rc;
+}
+
+// return file's modified time
+long int SystemTools::ModifiedTime(const std::string& filename)
+{
+  long int mt = 0;
+#ifdef _WIN32
+  WIN32_FILE_ATTRIBUTE_DATA fs;
+  if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(),
+                           GetFileExInfoStandard, &fs) != 0) {
+    mt = windows_filetime_to_posix_time(fs.ftLastWriteTime);
+  }
+#else
+  struct stat fs;
+  if (stat(filename.c_str(), &fs) == 0) {
+    mt = static_cast<long int>(fs.st_mtime);
+  }
+#endif
+  return mt;
+}
+
+// return file's creation time
+long int SystemTools::CreationTime(const std::string& filename)
+{
+  long int ct = 0;
+#ifdef _WIN32
+  WIN32_FILE_ATTRIBUTE_DATA fs;
+  if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(),
+                           GetFileExInfoStandard, &fs) != 0) {
+    ct = windows_filetime_to_posix_time(fs.ftCreationTime);
+  }
+#else
+  struct stat fs;
+  if (stat(filename.c_str(), &fs) == 0) {
+    ct = fs.st_ctime >= 0 ? static_cast<long int>(fs.st_ctime) : 0;
+  }
+#endif
+  return ct;
+}
+
+bool SystemTools::ConvertDateMacroString(const char* str, time_t* tmt)
+{
+  if (!str || !tmt || strlen(str) > 11) {
+    return false;
+  }
+
+  struct tm tmt2;
+
+  // __DATE__
+  // The compilation date of the current source file. The date is a string
+  // literal of the form Mmm dd yyyy. The month name Mmm is the same as for
+  // dates generated by the library function asctime declared in TIME.H.
+
+  // index:   012345678901
+  // format:  Mmm dd yyyy
+  // example: Dec 19 2003
+
+  static char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+  char buffer[12];
+  strcpy(buffer, str);
+
+  buffer[3] = 0;
+  char* ptr = strstr(month_names, buffer);
+  if (!ptr) {
+    return false;
+  }
+
+  int month = static_cast<int>((ptr - month_names) / 3);
+  int day = atoi(buffer + 4);
+  int year = atoi(buffer + 7);
+
+  tmt2.tm_isdst = -1;
+  tmt2.tm_hour = 0;
+  tmt2.tm_min = 0;
+  tmt2.tm_sec = 0;
+  tmt2.tm_wday = 0;
+  tmt2.tm_yday = 0;
+  tmt2.tm_mday = day;
+  tmt2.tm_mon = month;
+  tmt2.tm_year = year - 1900;
+
+  *tmt = mktime(&tmt2);
+  return true;
+}
+
+bool SystemTools::ConvertTimeStampMacroString(const char* str, time_t* tmt)
+{
+  if (!str || !tmt || strlen(str) > 26) {
+    return false;
+  }
+
+  struct tm tmt2;
+
+  // __TIMESTAMP__
+  // The date and time of the last modification of the current source file,
+  // expressed as a string literal in the form Ddd Mmm Date hh:mm:ss yyyy,
+  /// where Ddd is the abbreviated day of the week and Date is an integer
+  // from 1 to 31.
+
+  // index:   0123456789
+  //                    0123456789
+  //                              0123456789
+  // format:  Ddd Mmm Date hh:mm:ss yyyy
+  // example: Fri Dec 19 14:34:58 2003
+
+  static char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+  char buffer[27];
+  strcpy(buffer, str);
+
+  buffer[7] = 0;
+  char* ptr = strstr(month_names, buffer + 4);
+  if (!ptr) {
+    return false;
+  }
+
+  int month = static_cast<int>((ptr - month_names) / 3);
+  int day = atoi(buffer + 8);
+  int hour = atoi(buffer + 11);
+  int min = atoi(buffer + 14);
+  int sec = atoi(buffer + 17);
+  int year = atoi(buffer + 20);
+
+  tmt2.tm_isdst = -1;
+  tmt2.tm_hour = hour;
+  tmt2.tm_min = min;
+  tmt2.tm_sec = sec;
+  tmt2.tm_wday = 0;
+  tmt2.tm_yday = 0;
+  tmt2.tm_mday = day;
+  tmt2.tm_mon = month;
+  tmt2.tm_year = year - 1900;
+
+  *tmt = mktime(&tmt2);
+  return true;
+}
+
+std::string SystemTools::GetLastSystemError()
+{
+  int e = errno;
+  return strerror(e);
+}
+
+#ifdef _WIN32
+
+static bool IsJunction(const std::wstring& source)
+{
+#ifdef FSCTL_GET_REPARSE_POINT
+  const DWORD JUNCTION_ATTRS =
+    FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
+  DWORD attrs = GetFileAttributesW(source.c_str());
+  if (attrs == INVALID_FILE_ATTRIBUTES) {
+    return false;
+  }
+  if ((attrs & JUNCTION_ATTRS) != JUNCTION_ATTRS) {
+    return false;
+  }
+
+  // Adjust privileges so that we can succefully open junction points.
+  HANDLE token;
+  TOKEN_PRIVILEGES privs;
+  OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token);
+  LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &privs.Privileges[0].Luid);
+  privs.PrivilegeCount = 1;
+  privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+  AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL,
+                        NULL);
+  CloseHandle(token);
+
+  HANDLE dir = CreateFileW(
+    source.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING,
+    FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if (dir == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+
+  // Query whether this is a reparse point or not.
+  BYTE buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+  REPARSE_GUID_DATA_BUFFER* reparse_buffer = (REPARSE_GUID_DATA_BUFFER*)buffer;
+  DWORD sentinel;
+
+  BOOL success =
+    DeviceIoControl(dir, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse_buffer,
+                    MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &sentinel, NULL);
+
+  CloseHandle(dir);
+
+  return (success &&
+          (reparse_buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT));
+#else
+  return false;
+#endif
+}
+
+static bool DeleteJunction(const std::wstring& source)
+{
+#ifdef FSCTL_DELETE_REPARSE_POINT
+  // Adjust privileges so that we can succefully open junction points as
+  // read/write.
+  HANDLE token;
+  TOKEN_PRIVILEGES privs;
+  OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token);
+  LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &privs.Privileges[0].Luid);
+  privs.PrivilegeCount = 1;
+  privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+  AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL,
+                        NULL);
+  CloseHandle(token);
+
+  HANDLE dir = CreateFileW(
+    source.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+    FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if (dir == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+
+  // Set up the structure so that we can delete the junction.
+  std::vector<BYTE> buffer(REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, 0);
+  REPARSE_GUID_DATA_BUFFER* reparse_buffer =
+    (REPARSE_GUID_DATA_BUFFER*)&buffer[0];
+  DWORD sentinel;
+
+  reparse_buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+
+  BOOL success = DeviceIoControl(
+    dir, FSCTL_DELETE_REPARSE_POINT, reparse_buffer,
+    REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &sentinel, NULL);
+
+  CloseHandle(dir);
+
+  return !!success;
+#else
+  return false;
+#endif
+}
+
+#endif
+
+bool SystemTools::RemoveFile(const std::string& source)
+{
+#ifdef _WIN32
+  std::wstring const& ws = Encoding::ToWindowsExtendedPath(source);
+  if (DeleteFileW(ws.c_str())) {
+    return true;
+  }
+  DWORD err = GetLastError();
+  if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
+    return true;
+  }
+  if (err != ERROR_ACCESS_DENIED) {
+    return false;
+  }
+  /* The file may be read-only.  Try adding write permission.  */
+  mode_t mode;
+  if (!SystemTools::GetPermissions(source, mode) ||
+      !SystemTools::SetPermissions(source, S_IWRITE)) {
+    SetLastError(err);
+    return false;
+  }
+  if (IsJunction(ws) && DeleteJunction(ws)) {
+    return true;
+  }
+  if (DeleteFileW(ws.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND ||
+      GetLastError() == ERROR_PATH_NOT_FOUND) {
+    return true;
+  }
+  /* Try to restore the original permissions.  */
+  SystemTools::SetPermissions(source, mode);
+  SetLastError(err);
+  return false;
+#else
+  return unlink(source.c_str()) == 0 || errno == ENOENT;
+#endif
+}
+
+bool SystemTools::RemoveADirectory(const std::string& source)
+{
+  // Add write permission to the directory so we can modify its
+  // content to remove files and directories from it.
+  mode_t mode;
+  if (SystemTools::GetPermissions(source, mode)) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    mode |= S_IWRITE;
+#else
+    mode |= S_IWUSR;
+#endif
+    SystemTools::SetPermissions(source, mode);
+  }
+
+  Directory dir;
+#ifdef _WIN32
+  dir.Load(Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)));
+#else
+  dir.Load(source);
+#endif
+  size_t fileNum;
+  for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
+    if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") &&
+        strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) {
+      std::string fullPath = source;
+      fullPath += "/";
+      fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+      if (SystemTools::FileIsDirectory(fullPath) &&
+          !SystemTools::FileIsSymlink(fullPath)) {
+        if (!SystemTools::RemoveADirectory(fullPath)) {
+          return false;
+        }
+      } else {
+        if (!SystemTools::RemoveFile(fullPath)) {
+          return false;
+        }
+      }
+    }
+  }
+
+  return (Rmdir(source) == 0);
+}
+
+/**
+ */
+size_t SystemTools::GetMaximumFilePathLength()
+{
+  return KWSYS_SYSTEMTOOLS_MAXPATH;
+}
+
+/**
+ * Find the file the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the file if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+std::string SystemTools::FindName(const std::string& name,
+                                  const std::vector<std::string>& userPaths,
+                                  bool no_system_path)
+{
+  // Add the system search path to our path first
+  std::vector<std::string> path;
+  if (!no_system_path) {
+    SystemTools::GetPath(path, "CMAKE_FILE_PATH");
+    SystemTools::GetPath(path);
+  }
+  // now add the additional paths
+  {
+    for (std::vector<std::string>::const_iterator i = userPaths.begin();
+         i != userPaths.end(); ++i) {
+      path.push_back(*i);
+    }
+  }
+  // Add a trailing slash to all paths to aid the search process.
+  {
+    for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
+         ++i) {
+      std::string& p = *i;
+      if (p.empty() || *p.rbegin() != '/') {
+        p += "/";
+      }
+    }
+  }
+  // now look for the file
+  std::string tryPath;
+  for (std::vector<std::string>::const_iterator p = path.begin();
+       p != path.end(); ++p) {
+    tryPath = *p;
+    tryPath += name;
+    if (SystemTools::FileExists(tryPath)) {
+      return tryPath;
+    }
+  }
+  // Couldn't find the file.
+  return "";
+}
+
+/**
+ * Find the file the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the file if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+std::string SystemTools::FindFile(const std::string& name,
+                                  const std::vector<std::string>& userPaths,
+                                  bool no_system_path)
+{
+  std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+  if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) {
+    return SystemTools::CollapseFullPath(tryPath);
+  }
+  // Couldn't find the file.
+  return "";
+}
+
+/**
+ * Find the directory the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the directory if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+std::string SystemTools::FindDirectory(
+  const std::string& name, const std::vector<std::string>& userPaths,
+  bool no_system_path)
+{
+  std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+  if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) {
+    return SystemTools::CollapseFullPath(tryPath);
+  }
+  // Couldn't find the file.
+  return "";
+}
+
+/**
+ * Find the executable with the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the executable if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+std::string SystemTools::FindProgram(const char* nameIn,
+                                     const std::vector<std::string>& userPaths,
+                                     bool no_system_path)
+{
+  if (!nameIn || !*nameIn) {
+    return "";
+  }
+  return SystemTools::FindProgram(std::string(nameIn), userPaths,
+                                  no_system_path);
+}
+
+std::string SystemTools::FindProgram(const std::string& name,
+                                     const std::vector<std::string>& userPaths,
+                                     bool no_system_path)
+{
+  std::string tryPath;
+
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+  std::vector<std::string> extensions;
+  // check to see if the name already has a .xxx at
+  // the end of it
+  // on windows try .com then .exe
+  if (name.size() <= 3 || name[name.size() - 4] != '.') {
+    extensions.push_back(".com");
+    extensions.push_back(".exe");
+
+    // first try with extensions if the os supports them
+    for (std::vector<std::string>::iterator i = extensions.begin();
+         i != extensions.end(); ++i) {
+      tryPath = name;
+      tryPath += *i;
+      if (SystemTools::FileExists(tryPath, true)) {
+        return SystemTools::CollapseFullPath(tryPath);
+      }
+    }
+  }
+#endif
+
+  // now try just the name
+  if (SystemTools::FileExists(name, true)) {
+    return SystemTools::CollapseFullPath(name);
+  }
+  // now construct the path
+  std::vector<std::string> path;
+  // Add the system search path to our path.
+  if (!no_system_path) {
+    SystemTools::GetPath(path);
+  }
+  // now add the additional paths
+  {
+    for (std::vector<std::string>::const_iterator i = userPaths.begin();
+         i != userPaths.end(); ++i) {
+      path.push_back(*i);
+    }
+  }
+  // Add a trailing slash to all paths to aid the search process.
+  {
+    for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
+         ++i) {
+      std::string& p = *i;
+      if (p.empty() || *p.rbegin() != '/') {
+        p += "/";
+      }
+    }
+  }
+  // Try each path
+  for (std::vector<std::string>::iterator p = path.begin(); p != path.end();
+       ++p) {
+#ifdef _WIN32
+    // Remove double quotes from the path on windows
+    SystemTools::ReplaceString(*p, "\"", "");
+#endif
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+    // first try with extensions
+    for (std::vector<std::string>::iterator ext = extensions.begin();
+         ext != extensions.end(); ++ext) {
+      tryPath = *p;
+      tryPath += name;
+      tryPath += *ext;
+      if (SystemTools::FileExists(tryPath, true)) {
+        return SystemTools::CollapseFullPath(tryPath);
+      }
+    }
+#endif
+    // now try it without them
+    tryPath = *p;
+    tryPath += name;
+    if (SystemTools::FileExists(tryPath, true)) {
+      return SystemTools::CollapseFullPath(tryPath);
+    }
+  }
+  // Couldn't find the program.
+  return "";
+}
+
+std::string SystemTools::FindProgram(const std::vector<std::string>& names,
+                                     const std::vector<std::string>& path,
+                                     bool noSystemPath)
+{
+  for (std::vector<std::string>::const_iterator it = names.begin();
+       it != names.end(); ++it) {
+    // Try to find the program.
+    std::string result = SystemTools::FindProgram(*it, path, noSystemPath);
+    if (!result.empty()) {
+      return result;
+    }
+  }
+  return "";
+}
+
+/**
+ * Find the library with the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the library if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+std::string SystemTools::FindLibrary(const std::string& name,
+                                     const std::vector<std::string>& userPaths)
+{
+  // See if the executable exists as written.
+  if (SystemTools::FileExists(name, true)) {
+    return SystemTools::CollapseFullPath(name);
+  }
+
+  // Add the system search path to our path.
+  std::vector<std::string> path;
+  SystemTools::GetPath(path);
+  // now add the additional paths
+  {
+    for (std::vector<std::string>::const_iterator i = userPaths.begin();
+         i != userPaths.end(); ++i) {
+      path.push_back(*i);
+    }
+  }
+  // Add a trailing slash to all paths to aid the search process.
+  {
+    for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
+         ++i) {
+      std::string& p = *i;
+      if (p.empty() || *p.rbegin() != '/') {
+        p += "/";
+      }
+    }
+  }
+  std::string tryPath;
+  for (std::vector<std::string>::const_iterator p = path.begin();
+       p != path.end(); ++p) {
+#if defined(__APPLE__)
+    tryPath = *p;
+    tryPath += name;
+    tryPath += ".framework";
+    if (SystemTools::FileIsDirectory(tryPath)) {
+      return SystemTools::CollapseFullPath(tryPath);
+    }
+#endif
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
+    tryPath = *p;
+    tryPath += name;
+    tryPath += ".lib";
+    if (SystemTools::FileExists(tryPath, true)) {
+      return SystemTools::CollapseFullPath(tryPath);
+    }
+#else
+    tryPath = *p;
+    tryPath += "lib";
+    tryPath += name;
+    tryPath += ".so";
+    if (SystemTools::FileExists(tryPath, true)) {
+      return SystemTools::CollapseFullPath(tryPath);
+    }
+    tryPath = *p;
+    tryPath += "lib";
+    tryPath += name;
+    tryPath += ".a";
+    if (SystemTools::FileExists(tryPath, true)) {
+      return SystemTools::CollapseFullPath(tryPath);
+    }
+    tryPath = *p;
+    tryPath += "lib";
+    tryPath += name;
+    tryPath += ".sl";
+    if (SystemTools::FileExists(tryPath, true)) {
+      return SystemTools::CollapseFullPath(tryPath);
+    }
+    tryPath = *p;
+    tryPath += "lib";
+    tryPath += name;
+    tryPath += ".dylib";
+    if (SystemTools::FileExists(tryPath, true)) {
+      return SystemTools::CollapseFullPath(tryPath);
+    }
+    tryPath = *p;
+    tryPath += "lib";
+    tryPath += name;
+    tryPath += ".dll";
+    if (SystemTools::FileExists(tryPath, true)) {
+      return SystemTools::CollapseFullPath(tryPath);
+    }
+#endif
+  }
+
+  // Couldn't find the library.
+  return "";
+}
+
+std::string SystemTools::GetRealPath(const std::string& path,
+                                     std::string* errorMessage)
+{
+  std::string ret;
+  Realpath(path, ret, errorMessage);
+  return ret;
+}
+
+bool SystemTools::FileIsDirectory(const std::string& inName)
+{
+  if (inName.empty()) {
+    return false;
+  }
+  size_t length = inName.size();
+  const char* name = inName.c_str();
+
+  // Remove any trailing slash from the name except in a root component.
+  char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
+  std::string string_buffer;
+  size_t last = length - 1;
+  if (last > 0 && (name[last] == '/' || name[last] == '\\') &&
+      strcmp(name, "/") != 0 && name[last - 1] != ':') {
+    if (last < sizeof(local_buffer)) {
+      memcpy(local_buffer, name, last);
+      local_buffer[last] = '\0';
+      name = local_buffer;
+    } else {
+      string_buffer.append(name, last);
+      name = string_buffer.c_str();
+    }
+  }
+
+// Now check the file node type.
+#if defined(_WIN32)
+  DWORD attr =
+    GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str());
+  if (attr != INVALID_FILE_ATTRIBUTES) {
+    return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+#else
+  struct stat fs;
+  if (stat(name, &fs) == 0) {
+    return S_ISDIR(fs.st_mode);
+#endif
+  } else {
+    return false;
+  }
+}
+
+bool SystemTools::FileIsSymlink(const std::string& name)
+{
+#if defined(_WIN32)
+  DWORD attr =
+    GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str());
+  if (attr != INVALID_FILE_ATTRIBUTES) {
+    return (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+  } else {
+    return false;
+  }
+#else
+  struct stat fs;
+  if (lstat(name.c_str(), &fs) == 0) {
+    return S_ISLNK(fs.st_mode);
+  } else {
+    return false;
+  }
+#endif
+}
+
+bool SystemTools::FileIsFIFO(const std::string& name)
+{
+#if defined(_WIN32)
+  HANDLE hFile =
+    CreateFileW(Encoding::ToWide(name).c_str(), GENERIC_READ, FILE_SHARE_READ,
+                NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if (hFile == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+  const DWORD type = GetFileType(hFile);
+  CloseHandle(hFile);
+  return type == FILE_TYPE_PIPE;
+#else
+  struct stat fs;
+  if (lstat(name.c_str(), &fs) == 0) {
+    return S_ISFIFO(fs.st_mode);
+  } else {
+    return false;
+  }
+#endif
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::CreateSymlink(const std::string&, const std::string&)
+{
+  return false;
+}
+#else
+bool SystemTools::CreateSymlink(const std::string& origName,
+                                const std::string& newName)
+{
+  return symlink(origName.c_str(), newName.c_str()) >= 0;
+}
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::ReadSymlink(const std::string&, std::string&)
+{
+  return false;
+}
+#else
+bool SystemTools::ReadSymlink(const std::string& newName,
+                              std::string& origName)
+{
+  char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1];
+  int count = static_cast<int>(
+    readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH));
+  if (count >= 0) {
+    // Add null-terminator.
+    buf[count] = 0;
+    origName = buf;
+    return true;
+  } else {
+    return false;
+  }
+}
+#endif
+
+int SystemTools::ChangeDirectory(const std::string& dir)
+{
+  return Chdir(dir);
+}
+
+std::string SystemTools::GetCurrentWorkingDirectory(bool collapse)
+{
+  char buf[2048];
+  const char* cwd = Getcwd(buf, 2048);
+  std::string path;
+  if (cwd) {
+    path = cwd;
+  }
+  if (collapse) {
+    return SystemTools::CollapseFullPath(path);
+  }
+  return path;
+}
+
+std::string SystemTools::GetProgramPath(const std::string& in_name)
+{
+  std::string dir, file;
+  SystemTools::SplitProgramPath(in_name, dir, file);
+  return dir;
+}
+
+bool SystemTools::SplitProgramPath(const std::string& in_name,
+                                   std::string& dir, std::string& file, bool)
+{
+  dir = in_name;
+  file = "";
+  SystemTools::ConvertToUnixSlashes(dir);
+
+  if (!SystemTools::FileIsDirectory(dir)) {
+    std::string::size_type slashPos = dir.rfind("/");
+    if (slashPos != std::string::npos) {
+      file = dir.substr(slashPos + 1);
+      dir = dir.substr(0, slashPos);
+    } else {
+      file = dir;
+      dir = "";
+    }
+  }
+  if (!(dir.empty()) && !SystemTools::FileIsDirectory(dir)) {
+    std::string oldDir = in_name;
+    SystemTools::ConvertToUnixSlashes(oldDir);
+    dir = in_name;
+    return false;
+  }
+  return true;
+}
+
+bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut,
+                                  std::string& errorMsg, const char* exeName,
+                                  const char* buildDir,
+                                  const char* installPrefix)
+{
+  std::vector<std::string> failures;
+  std::string self = argv0 ? argv0 : "";
+  failures.push_back(self);
+  SystemTools::ConvertToUnixSlashes(self);
+  self = SystemTools::FindProgram(self);
+  if (!SystemTools::FileExists(self)) {
+    if (buildDir) {
+      std::string intdir = ".";
+#ifdef CMAKE_INTDIR
+      intdir = CMAKE_INTDIR;
+#endif
+      self = buildDir;
+      self += "/bin/";
+      self += intdir;
+      self += "/";
+      self += exeName;
+      self += SystemTools::GetExecutableExtension();
+    }
+  }
+  if (installPrefix) {
+    if (!SystemTools::FileExists(self)) {
+      failures.push_back(self);
+      self = installPrefix;
+      self += "/bin/";
+      self += exeName;
+    }
+  }
+  if (!SystemTools::FileExists(self)) {
+    failures.push_back(self);
+    std::ostringstream msg;
+    msg << "Can not find the command line program ";
+    if (exeName) {
+      msg << exeName;
+    }
+    msg << "\n";
+    if (argv0) {
+      msg << "  argv[0] = \"" << argv0 << "\"\n";
+    }
+    msg << "  Attempted paths:\n";
+    std::vector<std::string>::iterator i;
+    for (i = failures.begin(); i != failures.end(); ++i) {
+      msg << "    \"" << *i << "\"\n";
+    }
+    errorMsg = msg.str();
+    return false;
+  }
+  pathOut = self;
+  return true;
+}
+
+std::string SystemTools::CollapseFullPath(const std::string& in_relative)
+{
+  return SystemTools::CollapseFullPath(in_relative, 0);
+}
+
+void SystemTools::AddTranslationPath(const std::string& a,
+                                     const std::string& b)
+{
+  std::string path_a = a;
+  std::string path_b = b;
+  SystemTools::ConvertToUnixSlashes(path_a);
+  SystemTools::ConvertToUnixSlashes(path_b);
+  // First check this is a directory path, since we don't want the table to
+  // grow too fat
+  if (SystemTools::FileIsDirectory(path_a)) {
+    // Make sure the path is a full path and does not contain no '..'
+    // Ken--the following code is incorrect. .. can be in a valid path
+    // for example  /home/martink/MyHubba...Hubba/Src
+    if (SystemTools::FileIsFullPath(path_b) &&
+        path_b.find("..") == std::string::npos) {
+      // Before inserting make sure path ends with '/'
+      if (!path_a.empty() && *path_a.rbegin() != '/') {
+        path_a += '/';
+      }
+      if (!path_b.empty() && *path_b.rbegin() != '/') {
+        path_b += '/';
+      }
+      if (!(path_a == path_b)) {
+        SystemTools::TranslationMap->insert(
+          SystemToolsTranslationMap::value_type(path_a, path_b));
+      }
+    }
+  }
+}
+
+void SystemTools::AddKeepPath(const std::string& dir)
+{
+  std::string cdir;
+  Realpath(SystemTools::CollapseFullPath(dir).c_str(), cdir);
+  SystemTools::AddTranslationPath(cdir, dir);
+}
+
+void SystemTools::CheckTranslationPath(std::string& path)
+{
+  // Do not translate paths that are too short to have meaningful
+  // translations.
+  if (path.size() < 2) {
+    return;
+  }
+
+  // Always add a trailing slash before translation.  It does not
+  // matter if this adds an extra slash, but we do not want to
+  // translate part of a directory (like the foo part of foo-dir).
+  path += "/";
+
+  // In case a file was specified we still have to go through this:
+  // Now convert any path found in the table back to the one desired:
+  std::map<std::string, std::string>::const_iterator it;
+  for (it = SystemTools::TranslationMap->begin();
+       it != SystemTools::TranslationMap->end(); ++it) {
+    // We need to check of the path is a substring of the other path
+    if (path.find(it->first) == 0) {
+      path = path.replace(0, it->first.size(), it->second);
+    }
+  }
+
+  // Remove the trailing slash we added before.
+  path.erase(path.end() - 1, path.end());
+}
+
+static void SystemToolsAppendComponents(
+  std::vector<std::string>& out_components,
+  std::vector<std::string>::const_iterator first,
+  std::vector<std::string>::const_iterator last)
+{
+  static const std::string up = "..";
+  static const std::string cur = ".";
+  for (std::vector<std::string>::const_iterator i = first; i != last; ++i) {
+    if (*i == up) {
+      if (out_components.size() > 1) {
+        out_components.resize(out_components.size() - 1);
+      }
+    } else if (!i->empty() && *i != cur) {
+      out_components.push_back(*i);
+    }
+  }
+}
+
+std::string SystemTools::CollapseFullPath(const std::string& in_path,
+                                          const char* in_base)
+{
+  // Collect the output path components.
+  std::vector<std::string> out_components;
+
+  // Split the input path components.
+  std::vector<std::string> path_components;
+  SystemTools::SplitPath(in_path, path_components);
+
+  // If the input path is relative, start with a base path.
+  if (path_components[0].empty()) {
+    std::vector<std::string> base_components;
+    if (in_base) {
+      // Use the given base path.
+      SystemTools::SplitPath(in_base, base_components);
+    } else {
+      // Use the current working directory as a base path.
+      char buf[2048];
+      if (const char* cwd = Getcwd(buf, 2048)) {
+        SystemTools::SplitPath(cwd, base_components);
+      } else {
+        base_components.push_back("");
+      }
+    }
+
+    // Append base path components to the output path.
+    out_components.push_back(base_components[0]);
+    SystemToolsAppendComponents(out_components, base_components.begin() + 1,
+                                base_components.end());
+  }
+
+  // Append input path components to the output path.
+  SystemToolsAppendComponents(out_components, path_components.begin(),
+                              path_components.end());
+
+  // Transform the path back to a string.
+  std::string newPath = SystemTools::JoinPath(out_components);
+
+  // Update the translation table with this potentially new path.  I am not
+  // sure why this line is here, it seems really questionable, but yet I
+  // would put good money that if I remove it something will break, basically
+  // from what I can see it created a mapping from the collapsed path, to be
+  // replaced by the input path, which almost completely does the opposite of
+  // this function, the only thing preventing this from happening a lot is
+  // that if the in_path has a .. in it, then it is not added to the
+  // translation table. So for most calls this either does nothing due to the
+  // ..  or it adds a translation between identical paths as nothing was
+  // collapsed, so I am going to try to comment it out, and see what hits the
+  // fan, hopefully quickly.
+  // Commented out line below:
+  // SystemTools::AddTranslationPath(newPath, in_path);
+
+  SystemTools::CheckTranslationPath(newPath);
+#ifdef _WIN32
+  newPath = SystemTools::GetActualCaseForPath(newPath);
+  SystemTools::ConvertToUnixSlashes(newPath);
+#endif
+  // Return the reconstructed path.
+  return newPath;
+}
+
+std::string SystemTools::CollapseFullPath(const std::string& in_path,
+                                          const std::string& in_base)
+{
+  // Collect the output path components.
+  std::vector<std::string> out_components;
+
+  // Split the input path components.
+  std::vector<std::string> path_components;
+  SystemTools::SplitPath(in_path, path_components);
+
+  // If the input path is relative, start with a base path.
+  if (path_components[0].length() == 0) {
+    std::vector<std::string> base_components;
+    // Use the given base path.
+    SystemTools::SplitPath(in_base, base_components);
+
+    // Append base path components to the output path.
+    out_components.push_back(base_components[0]);
+    SystemToolsAppendComponents(out_components, base_components.begin() + 1,
+                                base_components.end());
+  }
+
+  // Append input path components to the output path.
+  SystemToolsAppendComponents(out_components, path_components.begin(),
+                              path_components.end());
+
+  // Transform the path back to a string.
+  std::string newPath = SystemTools::JoinPath(out_components);
+
+  // Update the translation table with this potentially new path.  I am not
+  // sure why this line is here, it seems really questionable, but yet I
+  // would put good money that if I remove it something will break, basically
+  // from what I can see it created a mapping from the collapsed path, to be
+  // replaced by the input path, which almost completely does the opposite of
+  // this function, the only thing preventing this from happening a lot is
+  // that if the in_path has a .. in it, then it is not added to the
+  // translation table. So for most calls this either does nothing due to the
+  // ..  or it adds a translation between identical paths as nothing was
+  // collapsed, so I am going to try to comment it out, and see what hits the
+  // fan, hopefully quickly.
+  // Commented out line below:
+  // SystemTools::AddTranslationPath(newPath, in_path);
+
+  SystemTools::CheckTranslationPath(newPath);
+#ifdef _WIN32
+  newPath = SystemTools::GetActualCaseForPath(newPath);
+  SystemTools::ConvertToUnixSlashes(newPath);
+#endif
+  // Return the reconstructed path.
+  return newPath;
+}
+
+// compute the relative path from here to there
+std::string SystemTools::RelativePath(const std::string& local,
+                                      const std::string& remote)
+{
+  if (!SystemTools::FileIsFullPath(local)) {
+    return "";
+  }
+  if (!SystemTools::FileIsFullPath(remote)) {
+    return "";
+  }
+
+  std::string l = SystemTools::CollapseFullPath(local);
+  std::string r = SystemTools::CollapseFullPath(remote);
+
+  // split up both paths into arrays of strings using / as a separator
+  std::vector<kwsys::String> localSplit =
+    SystemTools::SplitString(l, '/', true);
+  std::vector<kwsys::String> remoteSplit =
+    SystemTools::SplitString(r, '/', true);
+  std::vector<kwsys::String>
+    commonPath; // store shared parts of path in this array
+  std::vector<kwsys::String> finalPath; // store the final relative path here
+  // count up how many matching directory names there are from the start
+  unsigned int sameCount = 0;
+  while (((sameCount <= (localSplit.size() - 1)) &&
+          (sameCount <= (remoteSplit.size() - 1))) &&
+// for windows and apple do a case insensitive string compare
+#if defined(_WIN32) || defined(__APPLE__)
+         SystemTools::Strucmp(localSplit[sameCount].c_str(),
+                              remoteSplit[sameCount].c_str()) == 0
+#else
+         localSplit[sameCount] == remoteSplit[sameCount]
+#endif
+         ) {
+    // put the common parts of the path into the commonPath array
+    commonPath.push_back(localSplit[sameCount]);
+    // erase the common parts of the path from the original path arrays
+    localSplit[sameCount] = "";
+    remoteSplit[sameCount] = "";
+    sameCount++;
+  }
+
+  // If there is nothing in common at all then just return the full
+  // path.  This is the case only on windows when the paths have
+  // different drive letters.  On unix two full paths always at least
+  // have the root "/" in common so we will return a relative path
+  // that passes through the root directory.
+  if (sameCount == 0) {
+    return remote;
+  }
+
+  // for each entry that is not common in the local path
+  // add a ../ to the finalpath array, this gets us out of the local
+  // path into the remote dir
+  for (unsigned int i = 0; i < localSplit.size(); ++i) {
+    if (!localSplit[i].empty()) {
+      finalPath.push_back("../");
+    }
+  }
+  // for each entry that is not common in the remote path add it
+  // to the final path.
+  for (std::vector<String>::iterator vit = remoteSplit.begin();
+       vit != remoteSplit.end(); ++vit) {
+    if (!vit->empty()) {
+      finalPath.push_back(*vit);
+    }
+  }
+  std::string relativePath; // result string
+  // now turn the array of directories into a unix path by puttint /
+  // between each entry that does not already have one
+  for (std::vector<String>::iterator vit1 = finalPath.begin();
+       vit1 != finalPath.end(); ++vit1) {
+    if (!relativePath.empty() && *relativePath.rbegin() != '/') {
+      relativePath += "/";
+    }
+    relativePath += *vit1;
+  }
+  return relativePath;
+}
+
+#ifdef _WIN32
+static std::string GetCasePathName(std::string const& pathIn)
+{
+  std::string casePath;
+  std::vector<std::string> path_components;
+  SystemTools::SplitPath(pathIn, path_components);
+  if (path_components[0].empty()) // First component always exists.
+  {
+    // Relative paths cannot be converted.
+    casePath = pathIn;
+    return casePath;
+  }
+
+  // Start with root component.
+  std::vector<std::string>::size_type idx = 0;
+  casePath = path_components[idx++];
+  // make sure drive letter is always upper case
+  if (casePath.size() > 1 && casePath[1] == ':') {
+    casePath[0] = toupper(casePath[0]);
+  }
+  const char* sep = "";
+
+  // If network path, fill casePath with server/share so FindFirstFile
+  // will work after that.  Maybe someday call other APIs to get
+  // actual case of servers and shares.
+  if (path_components.size() > 2 && path_components[0] == "//") {
+    casePath += path_components[idx++];
+    casePath += "/";
+    casePath += path_components[idx++];
+    sep = "/";
+  }
+
+  // Convert case of all components that exist.
+  bool converting = true;
+  for (; idx < path_components.size(); idx++) {
+    casePath += sep;
+    sep = "/";
+
+    if (converting) {
+      // If path component contains wildcards, we skip matching
+      // because these filenames are not allowed on windows,
+      // and we do not want to match a different file.
+      if (path_components[idx].find('*') != std::string::npos ||
+          path_components[idx].find('?') != std::string::npos) {
+        converting = false;
+      } else {
+        std::string test_str = casePath;
+        test_str += path_components[idx];
+        WIN32_FIND_DATAW findData;
+        HANDLE hFind =
+          ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
+        if (INVALID_HANDLE_VALUE != hFind) {
+          path_components[idx] = Encoding::ToNarrow(findData.cFileName);
+          ::FindClose(hFind);
+        } else {
+          converting = false;
+        }
+      }
+    }
+
+    casePath += path_components[idx];
+  }
+  return casePath;
+}
+#endif
+
+//----------------------------------------------------------------------------
+std::string SystemTools::GetActualCaseForPath(const std::string& p)
+{
+#ifndef _WIN32
+  return p;
+#else
+  // Check to see if actual case has already been called
+  // for this path, and the result is stored in the PathCaseMap
+  SystemToolsPathCaseMap::iterator i = SystemTools::PathCaseMap->find(p);
+  if (i != SystemTools::PathCaseMap->end()) {
+    return i->second;
+  }
+  std::string casePath = GetCasePathName(p);
+  if (casePath.size() > MAX_PATH) {
+    return casePath;
+  }
+  (*SystemTools::PathCaseMap)[p] = casePath;
+  return casePath;
+#endif
+}
+
+//----------------------------------------------------------------------------
+const char* SystemTools::SplitPathRootComponent(const std::string& p,
+                                                std::string* root)
+{
+  // Identify the root component.
+  const char* c = p.c_str();
+  if ((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\')) {
+    // Network path.
+    if (root) {
+      *root = "//";
+    }
+    c += 2;
+  } else if (c[0] == '/' || c[0] == '\\') {
+    // Unix path (or Windows path w/out drive letter).
+    if (root) {
+      *root = "/";
+    }
+    c += 1;
+  } else if (c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\')) {
+    // Windows path.
+    if (root) {
+      (*root) = "_:/";
+      (*root)[0] = c[0];
+    }
+    c += 3;
+  } else if (c[0] && c[1] == ':') {
+    // Path relative to a windows drive working directory.
+    if (root) {
+      (*root) = "_:";
+      (*root)[0] = c[0];
+    }
+    c += 2;
+  } else if (c[0] == '~') {
+    // Home directory.  The returned root should always have a
+    // trailing slash so that appending components as
+    // c[0]c[1]/c[2]/... works.  The remaining path returned should
+    // skip the first slash if it exists:
+    //
+    //   "~"    : root = "~/" , return ""
+    //   "~/    : root = "~/" , return ""
+    //   "~/x   : root = "~/" , return "x"
+    //   "~u"   : root = "~u/", return ""
+    //   "~u/"  : root = "~u/", return ""
+    //   "~u/x" : root = "~u/", return "x"
+    size_t n = 1;
+    while (c[n] && c[n] != '/') {
+      ++n;
+    }
+    if (root) {
+      root->assign(c, n);
+      *root += '/';
+    }
+    if (c[n] == '/') {
+      ++n;
+    }
+    c += n;
+  } else {
+    // Relative path.
+    if (root) {
+      *root = "";
+    }
+  }
+
+  // Return the remaining path.
+  return c;
+}
+
+//----------------------------------------------------------------------------
+void SystemTools::SplitPath(const std::string& p,
+                            std::vector<std::string>& components,
+                            bool expand_home_dir)
+{
+  const char* c;
+  components.clear();
+
+  // Identify the root component.
+  {
+    std::string root;
+    c = SystemTools::SplitPathRootComponent(p, &root);
+
+    // Expand home directory references if requested.
+    if (expand_home_dir && !root.empty() && root[0] == '~') {
+      std::string homedir;
+      root = root.substr(0, root.size() - 1);
+      if (root.size() == 1) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+        if (!SystemTools::GetEnv("USERPROFILE", homedir))
+#endif
+          SystemTools::GetEnv("HOME", homedir);
+      }
+#ifdef HAVE_GETPWNAM
+      else if (passwd* pw = getpwnam(root.c_str() + 1)) {
+        if (pw->pw_dir) {
+          homedir = pw->pw_dir;
+        }
+      }
+#endif
+      if (!homedir.empty() &&
+          (*homedir.rbegin() == '/' || *homedir.rbegin() == '\\')) {
+        homedir.resize(homedir.size() - 1);
+      }
+      SystemTools::SplitPath(homedir, components);
+    } else {
+      components.push_back(root);
+    }
+  }
+
+  // Parse the remaining components.
+  const char* first = c;
+  const char* last = first;
+  for (; *last; ++last) {
+    if (*last == '/' || *last == '\\') {
+      // End of a component.  Save it.
+      components.push_back(std::string(first, last));
+      first = last + 1;
+    }
+  }
+
+  // Save the last component unless there were no components.
+  if (last != c) {
+    components.push_back(std::string(first, last));
+  }
+}
+
+//----------------------------------------------------------------------------
+std::string SystemTools::JoinPath(const std::vector<std::string>& components)
+{
+  return SystemTools::JoinPath(components.begin(), components.end());
+}
+
+//----------------------------------------------------------------------------
+std::string SystemTools::JoinPath(
+  std::vector<std::string>::const_iterator first,
+  std::vector<std::string>::const_iterator last)
+{
+  // Construct result in a single string.
+  std::string result;
+  size_t len = 0;
+  std::vector<std::string>::const_iterator i;
+  for (i = first; i != last; ++i) {
+    len += 1 + i->size();
+  }
+  result.reserve(len);
+
+  // The first two components do not add a slash.
+  if (first != last) {
+    result.append(*first++);
+  }
+  if (first != last) {
+    result.append(*first++);
+  }
+
+  // All remaining components are always separated with a slash.
+  while (first != last) {
+    result.append("/");
+    result.append((*first++));
+  }
+
+  // Return the concatenated result.
+  return result;
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::ComparePath(const std::string& c1, const std::string& c2)
+{
+#if defined(_WIN32) || defined(__APPLE__)
+#ifdef _MSC_VER
+  return _stricmp(c1.c_str(), c2.c_str()) == 0;
+#elif defined(__APPLE__) || defined(__GNUC__)
+  return strcasecmp(c1.c_str(), c2.c_str()) == 0;
+#else
+  return SystemTools::Strucmp(c1.c_str(), c2.c_str()) == 0;
+#endif
+#else
+  return c1 == c2;
+#endif
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::Split(const std::string& str,
+                        std::vector<std::string>& lines, char separator)
+{
+  std::string data(str);
+  std::string::size_type lpos = 0;
+  while (lpos < data.length()) {
+    std::string::size_type rpos = data.find_first_of(separator, lpos);
+    if (rpos == std::string::npos) {
+      // Line ends at end of string without a newline.
+      lines.push_back(data.substr(lpos));
+      return false;
+    } else {
+      // Line ends in a "\n", remove the character.
+      lines.push_back(data.substr(lpos, rpos - lpos));
+    }
+    lpos = rpos + 1;
+  }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+bool SystemTools::Split(const std::string& str,
+                        std::vector<std::string>& lines)
+{
+  std::string data(str);
+  std::string::size_type lpos = 0;
+  while (lpos < data.length()) {
+    std::string::size_type rpos = data.find_first_of("\n", lpos);
+    if (rpos == std::string::npos) {
+      // Line ends at end of string without a newline.
+      lines.push_back(data.substr(lpos));
+      return false;
+    }
+    if ((rpos > lpos) && (data[rpos - 1] == '\r')) {
+      // Line ends in a "\r\n" pair, remove both characters.
+      lines.push_back(data.substr(lpos, (rpos - 1) - lpos));
+    } else {
+      // Line ends in a "\n", remove the character.
+      lines.push_back(data.substr(lpos, rpos - lpos));
+    }
+    lpos = rpos + 1;
+  }
+  return true;
+}
+
+/**
+ * Return path of a full filename (no trailing slashes).
+ * Warning: returned path is converted to Unix slashes format.
+ */
+std::string SystemTools::GetFilenamePath(const std::string& filename)
+{
+  std::string fn = filename;
+  SystemTools::ConvertToUnixSlashes(fn);
+
+  std::string::size_type slash_pos = fn.rfind("/");
+  if (slash_pos != std::string::npos) {
+    std::string ret = fn.substr(0, slash_pos);
+    if (ret.size() == 2 && ret[1] == ':') {
+      return ret + '/';
+    }
+    if (ret.empty()) {
+      return "/";
+    }
+    return ret;
+  } else {
+    return "";
+  }
+}
+
+/**
+ * Return file name of a full filename (i.e. file name without path).
+ */
+std::string SystemTools::GetFilenameName(const std::string& filename)
+{
+#if defined(_WIN32)
+  std::string::size_type slash_pos = filename.find_last_of("/\\");
+#else
+  std::string::size_type slash_pos = filename.rfind('/');
+#endif
+  if (slash_pos != std::string::npos) {
+    return filename.substr(slash_pos + 1);
+  } else {
+    return filename;
+  }
+}
+
+/**
+ * Return file extension of a full filename (dot included).
+ * Warning: this is the longest extension (for example: .tar.gz)
+ */
+std::string SystemTools::GetFilenameExtension(const std::string& filename)
+{
+  std::string name = SystemTools::GetFilenameName(filename);
+  std::string::size_type dot_pos = name.find('.');
+  if (dot_pos != std::string::npos) {
+    return name.substr(dot_pos);
+  } else {
+    return "";
+  }
+}
+
+/**
+ * Return file extension of a full filename (dot included).
+ * Warning: this is the shortest extension (for example: .gz of .tar.gz)
+ */
+std::string SystemTools::GetFilenameLastExtension(const std::string& filename)
+{
+  std::string name = SystemTools::GetFilenameName(filename);
+  std::string::size_type dot_pos = name.rfind('.');
+  if (dot_pos != std::string::npos) {
+    return name.substr(dot_pos);
+  } else {
+    return "";
+  }
+}
+
+/**
+ * Return file name without extension of a full filename (i.e. without path).
+ * Warning: it considers the longest extension (for example: .tar.gz)
+ */
+std::string SystemTools::GetFilenameWithoutExtension(
+  const std::string& filename)
+{
+  std::string name = SystemTools::GetFilenameName(filename);
+  std::string::size_type dot_pos = name.find('.');
+  if (dot_pos != std::string::npos) {
+    return name.substr(0, dot_pos);
+  } else {
+    return name;
+  }
+}
+
+/**
+ * Return file name without extension of a full filename (i.e. without path).
+ * Warning: it considers the last extension (for example: removes .gz
+ * from .tar.gz)
+ */
+std::string SystemTools::GetFilenameWithoutLastExtension(
+  const std::string& filename)
+{
+  std::string name = SystemTools::GetFilenameName(filename);
+  std::string::size_type dot_pos = name.rfind('.');
+  if (dot_pos != std::string::npos) {
+    return name.substr(0, dot_pos);
+  } else {
+    return name;
+  }
+}
+
+bool SystemTools::FileHasSignature(const char* filename, const char* signature,
+                                   long offset)
+{
+  if (!filename || !signature) {
+    return false;
+  }
+
+  FILE* fp = Fopen(filename, "rb");
+  if (!fp) {
+    return false;
+  }
+
+  fseek(fp, offset, SEEK_SET);
+
+  bool res = false;
+  size_t signature_len = strlen(signature);
+  char* buffer = new char[signature_len];
+
+  if (fread(buffer, 1, signature_len, fp) == signature_len) {
+    res = (!strncmp(buffer, signature, signature_len) ? true : false);
+  }
+
+  delete[] buffer;
+
+  fclose(fp);
+  return res;
+}
+
+SystemTools::FileTypeEnum SystemTools::DetectFileType(const char* filename,
+                                                      unsigned long length,
+                                                      double percent_bin)
+{
+  if (!filename || percent_bin < 0) {
+    return SystemTools::FileTypeUnknown;
+  }
+
+  if (SystemTools::FileIsDirectory(filename)) {
+    return SystemTools::FileTypeUnknown;
+  }
+
+  FILE* fp = Fopen(filename, "rb");
+  if (!fp) {
+    return SystemTools::FileTypeUnknown;
+  }
+
+  // Allocate buffer and read bytes
+
+  unsigned char* buffer = new unsigned char[length];
+  size_t read_length = fread(buffer, 1, length, fp);
+  fclose(fp);
+  if (read_length == 0) {
+    delete[] buffer;
+    return SystemTools::FileTypeUnknown;
+  }
+
+  // Loop over contents and count
+
+  size_t text_count = 0;
+
+  const unsigned char* ptr = buffer;
+  const unsigned char* buffer_end = buffer + read_length;
+
+  while (ptr != buffer_end) {
+    if ((*ptr >= 0x20 && *ptr <= 0x7F) || *ptr == '\n' || *ptr == '\r' ||
+        *ptr == '\t') {
+      text_count++;
+    }
+    ptr++;
+  }
+
+  delete[] buffer;
+
+  double current_percent_bin = (static_cast<double>(read_length - text_count) /
+                                static_cast<double>(read_length));
+
+  if (current_percent_bin >= percent_bin) {
+    return SystemTools::FileTypeBinary;
+  }
+
+  return SystemTools::FileTypeText;
+}
+
+bool SystemTools::LocateFileInDir(const char* filename, const char* dir,
+                                  std::string& filename_found,
+                                  int try_filename_dirs)
+{
+  if (!filename || !dir) {
+    return false;
+  }
+
+  // Get the basename of 'filename'
+
+  std::string filename_base = SystemTools::GetFilenameName(filename);
+
+  // Check if 'dir' is really a directory
+  // If win32 and matches something like C:, accept it as a dir
+
+  std::string real_dir;
+  if (!SystemTools::FileIsDirectory(dir)) {
+#if defined(_WIN32)
+    size_t dir_len = strlen(dir);
+    if (dir_len < 2 || dir[dir_len - 1] != ':') {
+#endif
+      real_dir = SystemTools::GetFilenamePath(dir);
+      dir = real_dir.c_str();
+#if defined(_WIN32)
+    }
+#endif
+  }
+
+  // Try to find the file in 'dir'
+
+  bool res = false;
+  if (!filename_base.empty() && dir) {
+    size_t dir_len = strlen(dir);
+    int need_slash =
+      (dir_len && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\');
+
+    std::string temp = dir;
+    if (need_slash) {
+      temp += "/";
+    }
+    temp += filename_base;
+
+    if (SystemTools::FileExists(temp)) {
+      res = true;
+      filename_found = temp;
+    }
+
+    // If not found, we can try harder by appending part of the file to
+    // to the directory to look inside.
+    // Example: if we were looking for /foo/bar/yo.txt in /d1/d2, then
+    // try to find yo.txt in /d1/d2/bar, then /d1/d2/foo/bar, etc.
+
+    else if (try_filename_dirs) {
+      std::string filename_dir(filename);
+      std::string filename_dir_base;
+      std::string filename_dir_bases;
+      do {
+        filename_dir = SystemTools::GetFilenamePath(filename_dir);
+        filename_dir_base = SystemTools::GetFilenameName(filename_dir);
+#if defined(_WIN32)
+        if (filename_dir_base.empty() || *filename_dir_base.rbegin() == ':')
+#else
+        if (filename_dir_base.empty())
+#endif
+        {
+          break;
+        }
+
+        filename_dir_bases = filename_dir_base + "/" + filename_dir_bases;
+
+        temp = dir;
+        if (need_slash) {
+          temp += "/";
+        }
+        temp += filename_dir_bases;
+
+        res = SystemTools::LocateFileInDir(filename_base.c_str(), temp.c_str(),
+                                           filename_found, 0);
+
+      } while (!res && !filename_dir_base.empty());
+    }
+  }
+
+  return res;
+}
+
+bool SystemTools::FileIsFullPath(const std::string& in_name)
+{
+  return SystemTools::FileIsFullPath(in_name.c_str(), in_name.size());
+}
+
+bool SystemTools::FileIsFullPath(const char* in_name)
+{
+  return SystemTools::FileIsFullPath(in_name,
+                                     in_name[0] ? (in_name[1] ? 2 : 1) : 0);
+}
+
+bool SystemTools::FileIsFullPath(const char* in_name, size_t len)
+{
+#if defined(_WIN32) || defined(__CYGWIN__)
+  // On Windows, the name must be at least two characters long.
+  if (len < 2) {
+    return false;
+  }
+  if (in_name[1] == ':') {
+    return true;
+  }
+  if (in_name[0] == '\\') {
+    return true;
+  }
+#else
+  // On UNIX, the name must be at least one character long.
+  if (len < 1) {
+    return false;
+  }
+#endif
+#if !defined(_WIN32)
+  if (in_name[0] == '~') {
+    return true;
+  }
+#endif
+  // On UNIX, the name must begin in a '/'.
+  // On Windows, if the name begins in a '/', then it is a full
+  // network path.
+  if (in_name[0] == '/') {
+    return true;
+  }
+  return false;
+}
+
+bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  std::string tempPath = path; // create a buffer
+
+  // if the path passed in has quotes around it, first remove the quotes
+  if (!path.empty() && path[0] == '"' && *path.rbegin() == '"') {
+    tempPath = path.substr(1, path.length() - 2);
+  }
+
+  std::wstring wtempPath = Encoding::ToWide(tempPath);
+  DWORD ret = GetShortPathNameW(wtempPath.c_str(), NULL, 0);
+  std::vector<wchar_t> buffer(ret);
+  if (ret != 0) {
+    ret = GetShortPathNameW(wtempPath.c_str(), &buffer[0],
+                            static_cast<DWORD>(buffer.size()));
+  }
+
+  if (ret == 0) {
+    return false;
+  } else {
+    shortPath = Encoding::ToNarrow(&buffer[0]);
+    return true;
+  }
+#else
+  shortPath = path;
+  return true;
+#endif
+}
+
+void SystemTools::SplitProgramFromArgs(const std::string& path,
+                                       std::string& program, std::string& args)
+{
+  // see if this is a full path to a program
+  // if so then set program to path and args to nothing
+  if (SystemTools::FileExists(path)) {
+    program = path;
+    args = "";
+    return;
+  }
+  // Try to find the program in the path, note the program
+  // may have spaces in its name so we have to look for it
+  std::vector<std::string> e;
+  std::string findProg = SystemTools::FindProgram(path, e);
+  if (!findProg.empty()) {
+    program = findProg;
+    args = "";
+    return;
+  }
+
+  // Now try and peel off space separated chunks from the end of the string
+  // so the largest path possible is found allowing for spaces in the path
+  std::string dir = path;
+  std::string::size_type spacePos = dir.rfind(' ');
+  while (spacePos != std::string::npos) {
+    std::string tryProg = dir.substr(0, spacePos);
+    // See if the file exists
+    if (SystemTools::FileExists(tryProg)) {
+      program = tryProg;
+      // remove trailing spaces from program
+      std::string::size_type pos = program.size() - 1;
+      while (program[pos] == ' ') {
+        program.erase(pos);
+        pos--;
+      }
+      args = dir.substr(spacePos, dir.size() - spacePos);
+      return;
+    }
+    // Now try and find the program in the path
+    findProg = SystemTools::FindProgram(tryProg, e);
+    if (!findProg.empty()) {
+      program = findProg;
+      // remove trailing spaces from program
+      std::string::size_type pos = program.size() - 1;
+      while (program[pos] == ' ') {
+        program.erase(pos);
+        pos--;
+      }
+      args = dir.substr(spacePos, dir.size() - spacePos);
+      return;
+    }
+    // move past the space for the next search
+    spacePos--;
+    spacePos = dir.rfind(' ', spacePos);
+  }
+
+  program = "";
+  args = "";
+}
+
+std::string SystemTools::GetCurrentDateTime(const char* format)
+{
+  char buf[1024];
+  time_t t;
+  time(&t);
+  strftime(buf, sizeof(buf), format, localtime(&t));
+  return std::string(buf);
+}
+
+std::string SystemTools::MakeCidentifier(const std::string& s)
+{
+  std::string str(s);
+  if (str.find_first_of("0123456789") == 0) {
+    str = "_" + str;
+  }
+
+  std::string permited_chars("_"
+                             "abcdefghijklmnopqrstuvwxyz"
+                             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                             "0123456789");
+  std::string::size_type pos = 0;
+  while ((pos = str.find_first_not_of(permited_chars, pos)) !=
+         std::string::npos) {
+    str[pos] = '_';
+  }
+  return str;
+}
+
+// Due to a buggy stream library on the HP and another on Mac OS X, we
+// need this very carefully written version of getline.  Returns true
+// if any data were read before the end-of-file was reached.
+bool SystemTools::GetLineFromStream(std::istream& is, std::string& line,
+                                    bool* has_newline /* = 0 */,
+                                    long sizeLimit /* = -1 */)
+{
+  const int bufferSize = 1024;
+  char buffer[bufferSize];
+  bool haveData = false;
+  bool haveNewline = false;
+
+  // Start with an empty line.
+  line = "";
+
+  long leftToRead = sizeLimit;
+
+  // Early short circuit return if stream is no good. Just return
+  // false and the empty line. (Probably means caller tried to
+  // create a file stream with a non-existent file name...)
+  //
+  if (!is) {
+    if (has_newline) {
+      *has_newline = false;
+    }
+    return false;
+  }
+
+  // If no characters are read from the stream, the end of file has
+  // been reached.  Clear the fail bit just before reading.
+  while (!haveNewline && leftToRead != 0 &&
+         (static_cast<void>(is.clear(is.rdstate() & ~std::ios::failbit)),
+          static_cast<void>(is.getline(buffer, bufferSize)),
+          is.gcount() > 0)) {
+    // We have read at least one byte.
+    haveData = true;
+
+    // If newline character was read the gcount includes the character
+    // but the buffer does not: the end of line has been reached.
+    size_t length = strlen(buffer);
+    if (length < static_cast<size_t>(is.gcount())) {
+      haveNewline = true;
+    }
+
+    // Avoid storing a carriage return character.
+    if (length > 0 && buffer[length - 1] == '\r') {
+      buffer[length - 1] = 0;
+    }
+
+    // if we read too much then truncate the buffer
+    if (leftToRead > 0) {
+      if (static_cast<long>(length) > leftToRead) {
+        buffer[leftToRead] = 0;
+        leftToRead = 0;
+      } else {
+        leftToRead -= static_cast<long>(length);
+      }
+    }
+
+    // Append the data read to the line.
+    line.append(buffer);
+  }
+
+  // Return the results.
+  if (has_newline) {
+    *has_newline = haveNewline;
+  }
+  return haveData;
+}
+
+int SystemTools::GetTerminalWidth()
+{
+  int width = -1;
+#ifdef HAVE_TTY_INFO
+  struct winsize ws;
+  std::string columns; /* Unix98 environment variable */
+  if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0 && ws.ws_row > 0) {
+    width = ws.ws_col;
+  }
+  if (!isatty(STDOUT_FILENO)) {
+    width = -1;
+  }
+  if (SystemTools::GetEnv("COLUMNS", columns) && !columns.empty()) {
+    long t;
+    char* endptr;
+    t = strtol(columns.c_str(), &endptr, 0);
+    if (endptr && !*endptr && (t > 0) && (t < 1000)) {
+      width = static_cast<int>(t);
+    }
+  }
+  if (width < 9) {
+    width = -1;
+  }
+#endif
+  return width;
+}
+
+bool SystemTools::GetPermissions(const char* file, mode_t& mode)
+{
+  if (!file) {
+    return false;
+  }
+  return SystemTools::GetPermissions(std::string(file), mode);
+}
+
+bool SystemTools::GetPermissions(const std::string& file, mode_t& mode)
+{
+#if defined(_WIN32)
+  DWORD attr =
+    GetFileAttributesW(Encoding::ToWindowsExtendedPath(file).c_str());
+  if (attr == INVALID_FILE_ATTRIBUTES) {
+    return false;
+  }
+  if ((attr & FILE_ATTRIBUTE_READONLY) != 0) {
+    mode = (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
+  } else {
+    mode = (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6)) |
+      (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
+  }
+  if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+    mode |= S_IFDIR | (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6));
+  } else {
+    mode |= S_IFREG;
+  }
+  size_t dotPos = file.rfind('.');
+  const char* ext = dotPos == file.npos ? 0 : (file.c_str() + dotPos);
+  if (ext && (Strucmp(ext, ".exe") == 0 || Strucmp(ext, ".com") == 0 ||
+              Strucmp(ext, ".cmd") == 0 || Strucmp(ext, ".bat") == 0)) {
+    mode |= (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6));
+  }
+#else
+  struct stat st;
+  if (stat(file.c_str(), &st) < 0) {
+    return false;
+  }
+  mode = st.st_mode;
+#endif
+  return true;
+}
+
+bool SystemTools::SetPermissions(const char* file, mode_t mode,
+                                 bool honor_umask)
+{
+  if (!file) {
+    return false;
+  }
+  return SystemTools::SetPermissions(std::string(file), mode, honor_umask);
+}
+
+bool SystemTools::SetPermissions(const std::string& file, mode_t mode,
+                                 bool honor_umask)
+{
+  if (!SystemTools::PathExists(file)) {
+    return false;
+  }
+  if (honor_umask) {
+    mode_t currentMask = umask(0);
+    umask(currentMask);
+    mode &= ~currentMask;
+  }
+#ifdef _WIN32
+  if (_wchmod(Encoding::ToWindowsExtendedPath(file).c_str(), mode) < 0)
+#else
+  if (chmod(file.c_str(), mode) < 0)
+#endif
+  {
+    return false;
+  }
+
+  return true;
+}
+
+std::string SystemTools::GetParentDirectory(const std::string& fileOrDir)
+{
+  return SystemTools::GetFilenamePath(fileOrDir);
+}
+
+bool SystemTools::IsSubDirectory(const std::string& cSubdir,
+                                 const std::string& cDir)
+{
+  if (cDir.empty()) {
+    return false;
+  }
+  std::string subdir = cSubdir;
+  std::string dir = cDir;
+  SystemTools::ConvertToUnixSlashes(subdir);
+  SystemTools::ConvertToUnixSlashes(dir);
+  if (subdir.size() > dir.size() && subdir[dir.size()] == '/') {
+    std::string s = subdir.substr(0, dir.size());
+    return SystemTools::ComparePath(s, dir);
+  }
+  return false;
+}
+
+void SystemTools::Delay(unsigned int msec)
+{
+#ifdef _WIN32
+  Sleep(msec);
+#else
+  // The sleep function gives 1 second resolution and the usleep
+  // function gives 1e-6 second resolution but on some platforms has a
+  // maximum sleep time of 1 second.  This could be re-implemented to
+  // use select with masked signals or pselect to mask signals
+  // atomically.  If select is given empty sets and zero as the max
+  // file descriptor but a non-zero timeout it can be used to block
+  // for a precise amount of time.
+  if (msec >= 1000) {
+    sleep(msec / 1000);
+    usleep((msec % 1000) * 1000);
+  } else {
+    usleep(msec * 1000);
+  }
+#endif
+}
+
+std::string SystemTools::GetOperatingSystemNameAndVersion()
+{
+  std::string res;
+
+#ifdef _WIN32
+  char buffer[256];
+
+  OSVERSIONINFOEXA osvi;
+  BOOL bOsVersionInfoEx;
+
+  ZeroMemory(&osvi, sizeof(osvi));
+  osvi.dwOSVersionInfoSize = sizeof(osvi);
+
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(push)
+#ifdef __INTEL_COMPILER
+#pragma warning(disable : 1478)
+#else
+#pragma warning(disable : 4996)
+#endif
+#endif
+  bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA*)&osvi);
+  if (!bOsVersionInfoEx) {
+    return 0;
+  }
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+#pragma warning(pop)
+#endif
+
+  switch (osvi.dwPlatformId) {
+    // Test for the Windows NT product family.
+
+    case VER_PLATFORM_WIN32_NT:
+
+      // Test for the specific product family.
+      if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0) {
+        if (osvi.wProductType == VER_NT_WORKSTATION) {
+          res += "Microsoft Windows 10";
+        } else {
+          res += "Microsoft Windows Server 2016 family";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) {
+        if (osvi.wProductType == VER_NT_WORKSTATION) {
+          res += "Microsoft Windows 8.1";
+        } else {
+          res += "Microsoft Windows Server 2012 R2 family";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) {
+        if (osvi.wProductType == VER_NT_WORKSTATION) {
+          res += "Microsoft Windows 8";
+        } else {
+          res += "Microsoft Windows Server 2012 family";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) {
+        if (osvi.wProductType == VER_NT_WORKSTATION) {
+          res += "Microsoft Windows 7";
+        } else {
+          res += "Microsoft Windows Server 2008 R2 family";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
+        if (osvi.wProductType == VER_NT_WORKSTATION) {
+          res += "Microsoft Windows Vista";
+        } else {
+          res += "Microsoft Windows Server 2008 family";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
+        res += "Microsoft Windows Server 2003 family";
+      }
+
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+        res += "Microsoft Windows XP";
+      }
+
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
+        res += "Microsoft Windows 2000";
+      }
+
+      if (osvi.dwMajorVersion <= 4) {
+        res += "Microsoft Windows NT";
+      }
+
+      // Test for specific product on Windows NT 4.0 SP6 and later.
+
+      if (bOsVersionInfoEx) {
+        // Test for the workstation type.
+
+        if (osvi.wProductType == VER_NT_WORKSTATION) {
+          if (osvi.dwMajorVersion == 4) {
+            res += " Workstation 4.0";
+          } else if (osvi.dwMajorVersion == 5) {
+            if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
+              res += " Home Edition";
+            } else {
+              res += " Professional";
+            }
+          }
+        }
+
+        // Test for the server type.
+
+        else if (osvi.wProductType == VER_NT_SERVER) {
+          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
+            if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+              res += " Datacenter Edition";
+            } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+              res += " Enterprise Edition";
+            } else if (osvi.wSuiteMask == VER_SUITE_BLADE) {
+              res += " Web Edition";
+            } else {
+              res += " Standard Edition";
+            }
+          }
+
+          else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
+            if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+              res += " Datacenter Server";
+            } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+              res += " Advanced Server";
+            } else {
+              res += " Server";
+            }
+          }
+
+          else if (osvi.dwMajorVersion <= 4) // Windows NT 4.0
+          {
+            if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+              res += " Server 4.0, Enterprise Edition";
+            } else {
+              res += " Server 4.0";
+            }
+          }
+        }
+      }
+
+      // Test for specific product on Windows NT 4.0 SP5 and earlier
+
+      else {
+        HKEY hKey;
+#define BUFSIZE 80
+        wchar_t szProductType[BUFSIZE];
+        DWORD dwBufLen = BUFSIZE;
+        LONG lRet;
+
+        lRet =
+          RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                        L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+                        0, KEY_QUERY_VALUE, &hKey);
+        if (lRet != ERROR_SUCCESS) {
+          return 0;
+        }
+
+        lRet = RegQueryValueExW(hKey, L"ProductType", NULL, NULL,
+                                (LPBYTE)szProductType, &dwBufLen);
+
+        if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE)) {
+          return 0;
+        }
+
+        RegCloseKey(hKey);
+
+        if (lstrcmpiW(L"WINNT", szProductType) == 0) {
+          res += " Workstation";
+        }
+        if (lstrcmpiW(L"LANMANNT", szProductType) == 0) {
+          res += " Server";
+        }
+        if (lstrcmpiW(L"SERVERNT", szProductType) == 0) {
+          res += " Advanced Server";
+        }
+
+        res += " ";
+        sprintf(buffer, "%ld", osvi.dwMajorVersion);
+        res += buffer;
+        res += ".";
+        sprintf(buffer, "%ld", osvi.dwMinorVersion);
+        res += buffer;
+      }
+
+      // Display service pack (if any) and build number.
+
+      if (osvi.dwMajorVersion == 4 &&
+          lstrcmpiA(osvi.szCSDVersion, "Service Pack 6") == 0) {
+        HKEY hKey;
+        LONG lRet;
+
+        // Test for SP6 versus SP6a.
+
+        lRet = RegOpenKeyExW(
+          HKEY_LOCAL_MACHINE,
+          L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
+          0, KEY_QUERY_VALUE, &hKey);
+
+        if (lRet == ERROR_SUCCESS) {
+          res += " Service Pack 6a (Build ";
+          sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
+          res += buffer;
+          res += ")";
+        } else // Windows NT 4.0 prior to SP6a
+        {
+          res += " ";
+          res += osvi.szCSDVersion;
+          res += " (Build ";
+          sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
+          res += buffer;
+          res += ")";
+        }
+
+        RegCloseKey(hKey);
+      } else // Windows NT 3.51 and earlier or Windows 2000 and later
+      {
+        res += " ";
+        res += osvi.szCSDVersion;
+        res += " (Build ";
+        sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
+        res += buffer;
+        res += ")";
+      }
+
+      break;
+
+    // Test for the Windows 95 product family.
+
+    case VER_PLATFORM_WIN32_WINDOWS:
+
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
+        res += "Microsoft Windows 95";
+        if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') {
+          res += " OSR2";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
+        res += "Microsoft Windows 98";
+        if (osvi.szCSDVersion[1] == 'A') {
+          res += " SE";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
+        res += "Microsoft Windows Millennium Edition";
+      }
+      break;
+
+    case VER_PLATFORM_WIN32s:
+
+      res += "Microsoft Win32s";
+      break;
+  }
+#endif
+
+  return res;
+}
+
+// ----------------------------------------------------------------------
+bool SystemTools::ParseURLProtocol(const std::string& URL,
+                                   std::string& protocol,
+                                   std::string& dataglom)
+{
+  // match 0 entire url
+  // match 1 protocol
+  // match 2 dataglom following protocol://
+  kwsys::RegularExpression urlRe(VTK_URL_PROTOCOL_REGEX);
+
+  if (!urlRe.find(URL))
+    return false;
+
+  protocol = urlRe.match(1);
+  dataglom = urlRe.match(2);
+
+  return true;
+}
+
+// ----------------------------------------------------------------------
+bool SystemTools::ParseURL(const std::string& URL, std::string& protocol,
+                           std::string& username, std::string& password,
+                           std::string& hostname, std::string& dataport,
+                           std::string& database)
+{
+  kwsys::RegularExpression urlRe(VTK_URL_REGEX);
+  if (!urlRe.find(URL))
+    return false;
+
+  // match 0 URL
+  // match 1 protocol
+  // match 2 mangled user
+  // match 3 username
+  // match 4 mangled password
+  // match 5 password
+  // match 6 hostname
+  // match 7 mangled port
+  // match 8 dataport
+  // match 9 database name
+
+  protocol = urlRe.match(1);
+  username = urlRe.match(3);
+  password = urlRe.match(5);
+  hostname = urlRe.match(6);
+  dataport = urlRe.match(8);
+  database = urlRe.match(9);
+
+  return true;
+}
+
+// ----------------------------------------------------------------------
+// These must NOT be initialized.  Default initialization to zero is
+// necessary.
+static unsigned int SystemToolsManagerCount;
+SystemToolsTranslationMap* SystemTools::TranslationMap;
+#ifdef _WIN32
+SystemToolsPathCaseMap* SystemTools::PathCaseMap;
+SystemToolsEnvMap* SystemTools::EnvMap;
+#endif
+#ifdef __CYGWIN__
+SystemToolsTranslationMap* SystemTools::Cyg2Win32Map;
+#endif
+
+// SystemToolsManager manages the SystemTools singleton.
+// SystemToolsManager should be included in any translation unit
+// that will use SystemTools or that implements the singleton
+// pattern. It makes sure that the SystemTools singleton is created
+// before and destroyed after all other singletons in CMake.
+
+SystemToolsManager::SystemToolsManager()
+{
+  if (++SystemToolsManagerCount == 1) {
+    SystemTools::ClassInitialize();
+  }
+}
+
+SystemToolsManager::~SystemToolsManager()
+{
+  if (--SystemToolsManagerCount == 0) {
+    SystemTools::ClassFinalize();
+  }
+}
+
+#if defined(__VMS)
+// On VMS we configure the run time C library to be more UNIX like.
+// http://h71000.www7.hp.com/doc/732final/5763/5763pro_004.html
+extern "C" int decc$feature_get_index(char* name);
+extern "C" int decc$feature_set_value(int index, int mode, int value);
+static int SetVMSFeature(char* name, int value)
+{
+  int i;
+  errno = 0;
+  i = decc$feature_get_index(name);
+  return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0);
+}
+#endif
+
+void SystemTools::ClassInitialize()
+{
+#ifdef __VMS
+  SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1);
+#endif
+  // Allocate the translation map first.
+  SystemTools::TranslationMap = new SystemToolsTranslationMap;
+#ifdef _WIN32
+  SystemTools::PathCaseMap = new SystemToolsPathCaseMap;
+  SystemTools::EnvMap = new SystemToolsEnvMap;
+#endif
+#ifdef __CYGWIN__
+  SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap;
+#endif
+
+// Add some special translation paths for unix.  These are not added
+// for windows because drive letters need to be maintained.  Also,
+// there are not sym-links and mount points on windows anyway.
+#if !defined(_WIN32) || defined(__CYGWIN__)
+  // The tmp path is frequently a logical path so always keep it:
+  SystemTools::AddKeepPath("/tmp/");
+
+  // If the current working directory is a logical path then keep the
+  // logical name.
+  std::string pwd_str;
+  if (SystemTools::GetEnv("PWD", pwd_str)) {
+    char buf[2048];
+    if (const char* cwd = Getcwd(buf, 2048)) {
+      // The current working directory may be a logical path.  Find
+      // the shortest logical path that still produces the correct
+      // physical path.
+      std::string cwd_changed;
+      std::string pwd_changed;
+
+      // Test progressively shorter logical-to-physical mappings.
+      std::string cwd_str = cwd;
+      std::string pwd_path;
+      Realpath(pwd_str.c_str(), pwd_path);
+      while (cwd_str == pwd_path && cwd_str != pwd_str) {
+        // The current pair of paths is a working logical mapping.
+        cwd_changed = cwd_str;
+        pwd_changed = pwd_str;
+
+        // Strip off one directory level and see if the logical
+        // mapping still works.
+        pwd_str = SystemTools::GetFilenamePath(pwd_str);
+        cwd_str = SystemTools::GetFilenamePath(cwd_str);
+        Realpath(pwd_str.c_str(), pwd_path);
+      }
+
+      // Add the translation to keep the logical path name.
+      if (!cwd_changed.empty() && !pwd_changed.empty()) {
+        SystemTools::AddTranslationPath(cwd_changed, pwd_changed);
+      }
+    }
+  }
+#endif
+}
+
+void SystemTools::ClassFinalize()
+{
+  delete SystemTools::TranslationMap;
+#ifdef _WIN32
+  delete SystemTools::PathCaseMap;
+  delete SystemTools::EnvMap;
+#endif
+#ifdef __CYGWIN__
+  delete SystemTools::Cyg2Win32Map;
+#endif
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+#include <crtdbg.h>
+#include <stdio.h>
+#include <stdlib.h>
+namespace KWSYS_NAMESPACE {
+
+static int SystemToolsDebugReport(int, char* message, int*)
+{
+  fprintf(stderr, "%s", message);
+  fflush(stderr);
+  return 1; // no further reporting required
+}
+
+void SystemTools::EnableMSVCDebugHook()
+{
+  if (SystemTools::HasEnv("DART_TEST_FROM_DART") ||
+      SystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST")) {
+    _CrtSetReportHook(SystemToolsDebugReport);
+  }
+}
+
+} // namespace KWSYS_NAMESPACE
+#else
+namespace KWSYS_NAMESPACE {
+void SystemTools::EnableMSVCDebugHook()
+{
+}
+} // namespace KWSYS_NAMESPACE
+#endif
diff --git a/thirdparty/KWSys/adios2sys/SystemTools.hxx.in b/thirdparty/KWSys/adios2sys/SystemTools.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..0849e1da8feffc93045aa10497438ab00d819748
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/SystemTools.hxx.in
@@ -0,0 +1,1007 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_SystemTools_hxx
+#define @KWSYS_NAMESPACE@_SystemTools_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <@KWSYS_NAMESPACE@/String.hxx>
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+#include <unistd.h> // For access permissions for use with access()
+#endif
+
+// Required for va_list
+#include <stdarg.h>
+// Required for FILE*
+#include <stdio.h>
+#if !defined(va_list)
+// Some compilers move va_list into the std namespace and there is no way to
+// tell that this has been done. Playing with things being included before or
+// after stdarg.h does not solve things because we do not have control over
+// what the user does. This hack solves this problem by moving va_list to our
+// own namespace that is local for kwsys.
+namespace std {
+} // Required for platforms that do not have std namespace
+namespace @KWSYS_NAMESPACE@_VA_LIST {
+using namespace std;
+typedef va_list hack_va_list;
+}
+namespace @KWSYS_NAMESPACE@ {
+typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list;
+}
+#endif // va_list
+
+namespace @KWSYS_NAMESPACE@ {
+
+class SystemToolsTranslationMap;
+class SystemToolsPathCaseMap;
+class SystemToolsEnvMap;
+
+/** \class SystemToolsManager
+ * \brief Use to make sure SystemTools is initialized before it is used
+ * and is the last static object destroyed
+ */
+class @KWSYS_NAMESPACE@_EXPORT SystemToolsManager
+{
+public:
+  SystemToolsManager();
+  ~SystemToolsManager();
+};
+
+// This instance will show up in any translation unit that uses
+// SystemTools. It will make sure SystemTools is initialized
+// before it is used and is the last static object destroyed.
+static SystemToolsManager SystemToolsManagerInstance;
+
+// Flags for use with TestFileAccess.  Use a typedef in case any operating
+// system in the future needs a special type.  These are flags that may be
+// combined using the | operator.
+typedef int TestFilePermissions;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+// On Windows (VC and Borland), no system header defines these constants...
+static const TestFilePermissions TEST_FILE_OK = 0;
+static const TestFilePermissions TEST_FILE_READ = 4;
+static const TestFilePermissions TEST_FILE_WRITE = 2;
+static const TestFilePermissions TEST_FILE_EXECUTE = 1;
+#else
+// Standard POSIX constants
+static const TestFilePermissions TEST_FILE_OK = F_OK;
+static const TestFilePermissions TEST_FILE_READ = R_OK;
+static const TestFilePermissions TEST_FILE_WRITE = W_OK;
+static const TestFilePermissions TEST_FILE_EXECUTE = X_OK;
+#endif
+
+/** \class SystemTools
+ * \brief A collection of useful platform-independent system functions.
+ */
+class @KWSYS_NAMESPACE@_EXPORT SystemTools
+{
+public:
+  /** -----------------------------------------------------------------
+   *               String Manipulation Routines
+   *  -----------------------------------------------------------------
+   */
+
+  /**
+   * Replace symbols in str that are not valid in C identifiers as
+   * defined by the 1999 standard, ie. anything except [A-Za-z0-9_].
+   * They are replaced with `_' and if the first character is a digit
+   * then an underscore is prepended.  Note that this can produce
+   * identifiers that the standard reserves (_[A-Z].* and __.*).
+   */
+  static std::string MakeCidentifier(const std::string& s);
+
+  static std::string MakeCindentifier(const std::string& s)
+  {
+    return MakeCidentifier(s);
+  }
+
+  /**
+   * Replace replace all occurences of the string in the source string.
+   */
+  static void ReplaceString(std::string& source, const char* replace,
+                            const char* with);
+  static void ReplaceString(std::string& source, const std::string& replace,
+                            const std::string& with);
+
+  /**
+   * Return a capitalized string (i.e the first letter is uppercased,
+   * all other are lowercased).
+   */
+  static std::string Capitalized(const std::string&);
+
+  /**
+   * Return a 'capitalized words' string (i.e the first letter of each word
+   * is uppercased all other are left untouched though).
+   */
+  static std::string CapitalizedWords(const std::string&);
+
+  /**
+   * Return a 'uncapitalized words' string (i.e the first letter of each word
+   * is lowercased all other are left untouched though).
+   */
+  static std::string UnCapitalizedWords(const std::string&);
+
+  /**
+   * Return a lower case string
+   */
+  static std::string LowerCase(const std::string&);
+
+  /**
+   * Return a lower case string
+   */
+  static std::string UpperCase(const std::string&);
+
+  /**
+   * Count char in string
+   */
+  static size_t CountChar(const char* str, char c);
+
+  /**
+   * Remove some characters from a string.
+   * Return a pointer to the new resulting string (allocated with 'new')
+   */
+  static char* RemoveChars(const char* str, const char* toremove);
+
+  /**
+   * Remove remove all but 0->9, A->F characters from a string.
+   * Return a pointer to the new resulting string (allocated with 'new')
+   */
+  static char* RemoveCharsButUpperHex(const char* str);
+
+  /**
+   * Replace some characters by another character in a string (in-place)
+   * Return a pointer to string
+   */
+  static char* ReplaceChars(char* str, const char* toreplace,
+                            char replacement);
+
+  /**
+   * Returns true if str1 starts (respectively ends) with str2
+   */
+  static bool StringStartsWith(const char* str1, const char* str2);
+  static bool StringStartsWith(const std::string& str1, const char* str2);
+  static bool StringEndsWith(const char* str1, const char* str2);
+  static bool StringEndsWith(const std::string& str1, const char* str2);
+
+  /**
+   * Returns a pointer to the last occurence of str2 in str1
+   */
+  static const char* FindLastString(const char* str1, const char* str2);
+
+  /**
+   * Make a duplicate of the string similar to the strdup C function
+   * but use new to create the 'new' string, so one can use
+   * 'delete' to remove it. Returns 0 if the input is empty.
+   */
+  static char* DuplicateString(const char* str);
+
+  /**
+   * Return the string cropped to a given length by removing chars in the
+   * center of the string and replacing them with an ellipsis (...)
+   */
+  static std::string CropString(const std::string&, size_t max_len);
+
+  /** split a path by separator into an array of strings, default is /.
+      If isPath is true then the string is treated like a path and if
+      s starts with a / then the first element of the returned array will
+      be /, so /foo/bar will be [/, foo, bar]
+  */
+  static std::vector<String> SplitString(const std::string& s,
+                                         char separator = '/',
+                                         bool isPath = false);
+  /**
+   * Perform a case-independent string comparison
+   */
+  static int Strucmp(const char* s1, const char* s2);
+
+  /**
+   * Convert a string in __DATE__ or __TIMESTAMP__ format into a time_t.
+   * Return false on error, true on success
+   */
+  static bool ConvertDateMacroString(const char* str, time_t* tmt);
+  static bool ConvertTimeStampMacroString(const char* str, time_t* tmt);
+
+  /**
+   * Split a string on its newlines into multiple lines
+   * Return false only if the last line stored had no newline
+   */
+  static bool Split(const std::string& s, std::vector<std::string>& l);
+  static bool Split(const std::string& s, std::vector<std::string>& l,
+                    char separator);
+
+  /**
+   * Return string with space added between capitalized words
+   * (i.e. EatMyShorts becomes Eat My Shorts )
+   * (note that IEatShorts becomes IEat Shorts)
+   */
+  static std::string AddSpaceBetweenCapitalizedWords(const std::string&);
+
+  /**
+   * Append two or more strings and produce new one.
+   * Programmer must 'delete []' the resulting string, which was allocated
+   * with 'new'.
+   * Return 0 if inputs are empty or there was an error
+   */
+  static char* AppendStrings(const char* str1, const char* str2);
+  static char* AppendStrings(const char* str1, const char* str2,
+                             const char* str3);
+
+  /**
+   * Estimate the length of the string that will be produced
+   * from printing the given format string and arguments.  The
+   * returned length will always be at least as large as the string
+   * that will result from printing.
+   * WARNING: since va_arg is called to iterate of the argument list,
+   * you will not be able to use this 'ap' anymore from the beginning.
+   * It's up to you to call va_end though.
+   */
+  static int EstimateFormatLength(const char* format, va_list ap);
+
+  /**
+   * Escape specific characters in 'str'.
+   */
+  static std::string EscapeChars(const char* str, const char* chars_to_escape,
+                                 char escape_char = '\\');
+
+  /** -----------------------------------------------------------------
+   *               Filename Manipulation Routines
+   *  -----------------------------------------------------------------
+   */
+
+  /**
+   * Replace Windows file system slashes with Unix-style slashes.
+   */
+  static void ConvertToUnixSlashes(std::string& path);
+
+#ifdef _WIN32
+  /** Calls Encoding::ToWindowsExtendedPath.  */
+  static std::wstring ConvertToWindowsExtendedPath(const std::string&);
+#endif
+
+  /**
+   * For windows this calls ConvertToWindowsOutputPath and for unix
+   * it calls ConvertToUnixOutputPath
+   */
+  static std::string ConvertToOutputPath(const std::string&);
+
+  /**
+   * Convert the path to a string that can be used in a unix makefile.
+   * double slashes are removed, and spaces are escaped.
+   */
+  static std::string ConvertToUnixOutputPath(const std::string&);
+
+  /**
+   * Convert the path to string that can be used in a windows project or
+   * makefile.   Double slashes are removed if they are not at the start of
+   * the string, the slashes are converted to windows style backslashes, and
+   * if there are spaces in the string it is double quoted.
+   */
+  static std::string ConvertToWindowsOutputPath(const std::string&);
+
+  /**
+   * Return true if a path with the given name exists in the current directory.
+   */
+  static bool PathExists(const std::string& path);
+
+  /**
+   * Return true if a file exists in the current directory.
+   * If isFile = true, then make sure the file is a file and
+   * not a directory.  If isFile = false, then return true
+   * if it is a file or a directory.  Note that the file will
+   * also be checked for read access.  (Currently, this check
+   * for read access is only done on POSIX systems.)
+   */
+  static bool FileExists(const char* filename, bool isFile);
+  static bool FileExists(const std::string& filename, bool isFile);
+  static bool FileExists(const char* filename);
+  static bool FileExists(const std::string& filename);
+
+  /**
+   * Test if a file exists and can be accessed with the requested
+   * permissions.  Symbolic links are followed.  Returns true if
+   * the access test was successful.
+   *
+   * On POSIX systems (including Cygwin), this maps to the access
+   * function.  On Windows systems, all existing files are
+   * considered readable, and writable files are considered to
+   * have the read-only file attribute cleared.
+   */
+  static bool TestFileAccess(const char* filename,
+                             TestFilePermissions permissions);
+  static bool TestFileAccess(const std::string& filename,
+                             TestFilePermissions permissions);
+/**
+ * Cross platform wrapper for stat struct
+ */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#if defined(__BORLANDC__)
+  typedef struct stati64 Stat_t;
+#else
+  typedef struct _stat64 Stat_t;
+#endif
+#else
+  typedef struct stat Stat_t;
+#endif
+
+  /**
+   * Cross platform wrapper for stat system call
+   *
+   * On Windows this may not work for paths longer than 250 characters
+   * due to limitations of the underlying '_wstat64' call.
+   */
+  static int Stat(const char* path, Stat_t* buf);
+  static int Stat(const std::string& path, Stat_t* buf);
+
+/**
+ * Converts Cygwin path to Win32 path. Uses dictionary container for
+ * caching and calls to cygwin_conv_to_win32_path from Cygwin dll
+ * for actual translation.  Returns true on success, else false.
+ */
+#ifdef __CYGWIN__
+  static bool PathCygwinToWin32(const char* path, char* win32_path);
+#endif
+
+  /**
+   * Return file length
+   */
+  static unsigned long FileLength(const std::string& filename);
+
+  /**
+     Change the modification time or create a file
+  */
+  static bool Touch(const std::string& filename, bool create);
+
+  /**
+   *  Compare file modification times.
+   *  Return true for successful comparison and false for error.
+   *  When true is returned, result has -1, 0, +1 for
+   *  f1 older, same, or newer than f2.
+   */
+  static bool FileTimeCompare(const std::string& f1, const std::string& f2,
+                              int* result);
+
+  /**
+   *  Get the file extension (including ".") needed for an executable
+   *  on the current platform ("" for unix, ".exe" for Windows).
+   */
+  static const char* GetExecutableExtension();
+
+  /**
+   * Given a path on a Windows machine, return the actual case of
+   * the path as it exists on disk.  Path components that do not
+   * exist on disk are returned unchanged.  Relative paths are always
+   * returned unchanged.  Drive letters are always made upper case.
+   * This does nothing on non-Windows systems but return the path.
+   */
+  static std::string GetActualCaseForPath(const std::string& path);
+
+  /**
+   * Given the path to a program executable, get the directory part of
+   * the path with the file stripped off.  If there is no directory
+   * part, the empty string is returned.
+   */
+  static std::string GetProgramPath(const std::string&);
+  static bool SplitProgramPath(const std::string& in_name, std::string& dir,
+                               std::string& file, bool errorReport = true);
+
+  /**
+   *  Given argv[0] for a unix program find the full path to a running
+   *  executable.  argv0 can be null for windows WinMain programs
+   *  in this case GetModuleFileName will be used to find the path
+   *  to the running executable.  If argv0 is not a full path,
+   *  then this will try to find the full path.  If the path is not
+   *  found false is returned, if found true is returned.  An error
+   *  message of the attempted paths is stored in errorMsg.
+   *  exeName is the name of the executable.
+   *  buildDir is a possibly null path to the build directory.
+   *  installPrefix is a possibly null pointer to the install directory.
+   */
+  static bool FindProgramPath(const char* argv0, std::string& pathOut,
+                              std::string& errorMsg, const char* exeName = 0,
+                              const char* buildDir = 0,
+                              const char* installPrefix = 0);
+
+  /**
+   * Given a path to a file or directory, convert it to a full path.
+   * This collapses away relative paths relative to the cwd argument
+   * (which defaults to the current working directory).  The full path
+   * is returned.
+   */
+  static std::string CollapseFullPath(const std::string& in_relative);
+  static std::string CollapseFullPath(const std::string& in_relative,
+                                      const char* in_base);
+  static std::string CollapseFullPath(const std::string& in_relative,
+                                      const std::string& in_base);
+
+  /**
+   * Get the real path for a given path, removing all symlinks.  In
+   * the event of an error (non-existent path, permissions issue,
+   * etc.) the original path is returned if errorMessage pointer is
+   * NULL.  Otherwise empty string is returned and errorMessage
+   * contains error description.
+   */
+  static std::string GetRealPath(const std::string& path,
+                                 std::string* errorMessage = 0);
+
+  /**
+   * Split a path name into its root component and the rest of the
+   * path.  The root component is one of the following:
+   *    "/"   = UNIX full path
+   *    "c:/" = Windows full path (can be any drive letter)
+   *    "c:"  = Windows drive-letter relative path (can be any drive letter)
+   *    "//"  = Network path
+   *    "~/"  = Home path for current user
+   *    "~u/" = Home path for user 'u'
+   *    ""    = Relative path
+   *
+   * A pointer to the rest of the path after the root component is
+   * returned.  The root component is stored in the "root" string if
+   * given.
+   */
+  static const char* SplitPathRootComponent(const std::string& p,
+                                            std::string* root = 0);
+
+  /**
+   * Split a path name into its basic components.  The first component
+   * always exists and is the root returned by SplitPathRootComponent.
+   * The remaining components form the path.  If there is a trailing
+   * slash then the last component is the empty string.  The
+   * components can be recombined as "c[0]c[1]/c[2]/.../c[n]" to
+   * produce the original path.  Home directory references are
+   * automatically expanded if expand_home_dir is true and this
+   * platform supports them.
+   */
+  static void SplitPath(const std::string& p,
+                        std::vector<std::string>& components,
+                        bool expand_home_dir = true);
+
+  /**
+   * Join components of a path name into a single string.  See
+   * SplitPath for the format of the components.
+   */
+  static std::string JoinPath(const std::vector<std::string>& components);
+  static std::string JoinPath(std::vector<std::string>::const_iterator first,
+                              std::vector<std::string>::const_iterator last);
+
+  /**
+   * Compare a path or components of a path.
+   */
+  static bool ComparePath(const std::string& c1, const std::string& c2);
+
+  /**
+   * Return path of a full filename (no trailing slashes)
+   */
+  static std::string GetFilenamePath(const std::string&);
+
+  /**
+   * Return file name of a full filename (i.e. file name without path)
+   */
+  static std::string GetFilenameName(const std::string&);
+
+  /**
+   * Split a program from its arguments and handle spaces in the paths
+   */
+  static void SplitProgramFromArgs(const std::string& path,
+                                   std::string& program, std::string& args);
+
+  /**
+   * Return longest file extension of a full filename (dot included)
+   */
+  static std::string GetFilenameExtension(const std::string&);
+
+  /**
+   * Return shortest file extension of a full filename (dot included)
+   */
+  static std::string GetFilenameLastExtension(const std::string& filename);
+
+  /**
+   * Return file name without extension of a full filename
+   */
+  static std::string GetFilenameWithoutExtension(const std::string&);
+
+  /**
+   * Return file name without its last (shortest) extension
+   */
+  static std::string GetFilenameWithoutLastExtension(const std::string&);
+
+  /**
+   * Return whether the path represents a full path (not relative)
+   */
+  static bool FileIsFullPath(const std::string&);
+  static bool FileIsFullPath(const char*);
+
+  /**
+   * For windows return the short path for the given path,
+   * Unix just a pass through
+   */
+  static bool GetShortPath(const std::string& path, std::string& result);
+
+  /**
+   * Read line from file. Make sure to get everything. Due to a buggy stream
+   * library on the HP and another on Mac OS X, we need this very carefully
+   * written version of getline. Returns true if any data were read before the
+   * end-of-file was reached. If the has_newline argument is specified, it will
+   * be true when the line read had a newline character.
+   */
+  static bool GetLineFromStream(std::istream& istr, std::string& line,
+                                bool* has_newline = 0, long sizeLimit = -1);
+
+  /**
+   * Get the parent directory of the directory or file
+   */
+  static std::string GetParentDirectory(const std::string& fileOrDir);
+
+  /**
+   * Check if the given file or directory is in subdirectory of dir
+   */
+  static bool IsSubDirectory(const std::string& fileOrDir,
+                             const std::string& dir);
+
+  /** -----------------------------------------------------------------
+   *               File Manipulation Routines
+   *  -----------------------------------------------------------------
+   */
+
+  /**
+   * Open a file considering unicode.
+   */
+  static FILE* Fopen(const std::string& file, const char* mode);
+
+  /**
+   * Make a new directory if it is not there.  This function
+   * can make a full path even if none of the directories existed
+   * prior to calling this function.
+   */
+  static bool MakeDirectory(const char* path);
+  static bool MakeDirectory(const std::string& path);
+
+  /**
+   * Copy the source file to the destination file only
+   * if the two files differ.
+   */
+  static bool CopyFileIfDifferent(const std::string& source,
+                                  const std::string& destination);
+
+  /**
+   * Compare the contents of two files.  Return true if different
+   */
+  static bool FilesDiffer(const std::string& source,
+                          const std::string& destination);
+
+  /**
+   * Return true if the two files are the same file
+   */
+  static bool SameFile(const std::string& file1, const std::string& file2);
+
+  /**
+   * Copy a file.
+   */
+  static bool CopyFileAlways(const std::string& source,
+                             const std::string& destination);
+
+  /**
+   * Copy a file.  If the "always" argument is true the file is always
+   * copied.  If it is false, the file is copied only if it is new or
+   * has changed.
+   */
+  static bool CopyAFile(const std::string& source,
+                        const std::string& destination, bool always = true);
+
+  /**
+   * Copy content directory to another directory with all files and
+   * subdirectories.  If the "always" argument is true all files are
+   * always copied.  If it is false, only files that have changed or
+   * are new are copied.
+   */
+  static bool CopyADirectory(const std::string& source,
+                             const std::string& destination,
+                             bool always = true);
+
+  /**
+   * Remove a file
+   */
+  static bool RemoveFile(const std::string& source);
+
+  /**
+   * Remove a directory
+   */
+  static bool RemoveADirectory(const std::string& source);
+
+  /**
+   * Get the maximum full file path length
+   */
+  static size_t GetMaximumFilePathLength();
+
+  /**
+   * Find a file in the system PATH, with optional extra paths
+   */
+  static std::string FindFile(
+    const std::string& name,
+    const std::vector<std::string>& path = std::vector<std::string>(),
+    bool no_system_path = false);
+
+  /**
+   * Find a directory in the system PATH, with optional extra paths
+   */
+  static std::string FindDirectory(
+    const std::string& name,
+    const std::vector<std::string>& path = std::vector<std::string>(),
+    bool no_system_path = false);
+
+  /**
+   * Find an executable in the system PATH, with optional extra paths
+   */
+  static std::string FindProgram(
+    const char* name,
+    const std::vector<std::string>& path = std::vector<std::string>(),
+    bool no_system_path = false);
+  static std::string FindProgram(
+    const std::string& name,
+    const std::vector<std::string>& path = std::vector<std::string>(),
+    bool no_system_path = false);
+  static std::string FindProgram(
+    const std::vector<std::string>& names,
+    const std::vector<std::string>& path = std::vector<std::string>(),
+    bool no_system_path = false);
+
+  /**
+   * Find a library in the system PATH, with optional extra paths
+   */
+  static std::string FindLibrary(const std::string& name,
+                                 const std::vector<std::string>& path);
+
+  /**
+   * Return true if the file is a directory
+   */
+  static bool FileIsDirectory(const std::string& name);
+
+  /**
+   * Return true if the file is a symlink
+   */
+  static bool FileIsSymlink(const std::string& name);
+
+  /**
+   * Return true if the file is a FIFO
+   */
+  static bool FileIsFIFO(const std::string& name);
+
+  /**
+   * Return true if the file has a given signature (first set of bytes)
+   */
+  static bool FileHasSignature(const char* filename, const char* signature,
+                               long offset = 0);
+
+  /**
+   * Attempt to detect and return the type of a file.
+   * Up to 'length' bytes are read from the file, if more than 'percent_bin' %
+   * of the bytes are non-textual elements, the file is considered binary,
+   * otherwise textual. Textual elements are bytes in the ASCII [0x20, 0x7E]
+   * range, but also \\n, \\r, \\t.
+   * The algorithm is simplistic, and should probably check for usual file
+   * extensions, 'magic' signature, unicode, etc.
+   */
+  enum FileTypeEnum
+  {
+    FileTypeUnknown,
+    FileTypeBinary,
+    FileTypeText
+  };
+  static SystemTools::FileTypeEnum DetectFileType(const char* filename,
+                                                  unsigned long length = 256,
+                                                  double percent_bin = 0.05);
+
+  /**
+   * Create a symbolic link if the platform supports it.  Returns whether
+   * creation succeeded.
+   */
+  static bool CreateSymlink(const std::string& origName,
+                            const std::string& newName);
+
+  /**
+   * Read the contents of a symbolic link.  Returns whether reading
+   * succeeded.
+   */
+  static bool ReadSymlink(const std::string& newName, std::string& origName);
+
+  /**
+   * Try to locate the file 'filename' in the directory 'dir'.
+   * If 'filename' is a fully qualified filename, the basename of the file is
+   * used to check for its existence in 'dir'.
+   * If 'dir' is not a directory, GetFilenamePath() is called on 'dir' to
+   * get its directory first (thus, you can pass a filename as 'dir', as
+   * a convenience).
+   * 'filename_found' is assigned the fully qualified name/path of the file
+   * if it is found (not touched otherwise).
+   * If 'try_filename_dirs' is true, try to find the file using the
+   * components of its path, i.e. if we are looking for c:/foo/bar/bill.txt,
+   * first look for bill.txt in 'dir', then in 'dir'/bar, then in 'dir'/foo/bar
+   * etc.
+   * Return true if the file was found, false otherwise.
+   */
+  static bool LocateFileInDir(const char* filename, const char* dir,
+                              std::string& filename_found,
+                              int try_filename_dirs = 0);
+
+  /** compute the relative path from local to remote.  local must
+      be a directory.  remote can be a file or a directory.
+      Both remote and local must be full paths.  Basically, if
+      you are in directory local and you want to access the file in remote
+      what is the relative path to do that.  For example:
+      /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
+      from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
+  */
+  static std::string RelativePath(const std::string& local,
+                                  const std::string& remote);
+
+  /**
+   * Return file's modified time
+   */
+  static long int ModifiedTime(const std::string& filename);
+
+  /**
+   * Return file's creation time (Win32: works only for NTFS, not FAT)
+   */
+  static long int CreationTime(const std::string& filename);
+
+/**
+ * Visual C++ does not define mode_t (note that Borland does, however).
+ */
+#if defined(_MSC_VER)
+  typedef unsigned short mode_t;
+#endif
+
+  /**
+   * Get and set permissions of the file.  If honor_umask is set, the umask
+   * is queried and applied to the given permissions.  Returns false if
+   * failure.
+   *
+   * WARNING:  A non-thread-safe method is currently used to get the umask
+   * if a honor_umask parameter is set to true.
+   */
+  static bool GetPermissions(const char* file, mode_t& mode);
+  static bool GetPermissions(const std::string& file, mode_t& mode);
+  static bool SetPermissions(const char* file, mode_t mode,
+                             bool honor_umask = false);
+  static bool SetPermissions(const std::string& file, mode_t mode,
+                             bool honor_umask = false);
+
+  /** -----------------------------------------------------------------
+   *               Time Manipulation Routines
+   *  -----------------------------------------------------------------
+   */
+
+  /** Get current time in seconds since Posix Epoch (Jan 1, 1970).  */
+  static double GetTime();
+
+  /**
+   * Get current date/time
+   */
+  static std::string GetCurrentDateTime(const char* format);
+
+  /** -----------------------------------------------------------------
+   *               Registry Manipulation Routines
+   *  -----------------------------------------------------------------
+   */
+
+  /**
+   * Specify access to the 32-bit or 64-bit application view of
+   * registry values.  The default is to match the currently running
+   * binary type.
+   */
+  enum KeyWOW64
+  {
+    KeyWOW64_Default,
+    KeyWOW64_32,
+    KeyWOW64_64
+  };
+
+  /**
+   * Get a list of subkeys.
+   */
+  static bool GetRegistrySubKeys(const std::string& key,
+                                 std::vector<std::string>& subkeys,
+                                 KeyWOW64 view = KeyWOW64_Default);
+
+  /**
+   * Read a registry value
+   */
+  static bool ReadRegistryValue(const std::string& key, std::string& value,
+                                KeyWOW64 view = KeyWOW64_Default);
+
+  /**
+   * Write a registry value
+   */
+  static bool WriteRegistryValue(const std::string& key,
+                                 const std::string& value,
+                                 KeyWOW64 view = KeyWOW64_Default);
+
+  /**
+   * Delete a registry value
+   */
+  static bool DeleteRegistryValue(const std::string& key,
+                                  KeyWOW64 view = KeyWOW64_Default);
+
+  /** -----------------------------------------------------------------
+   *               Environment Manipulation Routines
+   *  -----------------------------------------------------------------
+   */
+
+  /**
+   *  Add the paths from the environment variable PATH to the
+   *  string vector passed in.  If env is set then the value
+   *  of env will be used instead of PATH.
+   */
+  static void GetPath(std::vector<std::string>& path, const char* env = 0);
+
+  /**
+   * Read an environment variable
+   */
+  static const char* GetEnv(const char* key);
+  static const char* GetEnv(const std::string& key);
+  static bool GetEnv(const char* key, std::string& result);
+  static bool GetEnv(const std::string& key, std::string& result);
+  static bool HasEnv(const char* key);
+  static bool HasEnv(const std::string& key);
+
+  /** Put a string into the environment
+      of the form var=value */
+  static bool PutEnv(const std::string& env);
+
+  /** Remove a string from the environment.
+      Input is of the form "var" or "var=value" (value is ignored). */
+  static bool UnPutEnv(const std::string& env);
+
+  /**
+   * Get current working directory CWD
+   */
+  static std::string GetCurrentWorkingDirectory(bool collapse = true);
+
+  /**
+   * Change directory to the directory specified
+   */
+  static int ChangeDirectory(const std::string& dir);
+
+  /**
+   * Get the result of strerror(errno)
+   */
+  static std::string GetLastSystemError();
+
+  /**
+   * When building DEBUG with MSVC, this enables a hook that prevents
+   * error dialogs from popping up if the program is being run from
+   * DART.
+   */
+  static void EnableMSVCDebugHook();
+
+  /**
+   * Get the width of the terminal window. The code may or may not work, so
+   * make sure you have some resonable defaults prepared if the code returns
+   * some bogus size.
+   */
+  static int GetTerminalWidth();
+
+  /**
+   * Add an entry in the path translation table.
+   */
+  static void AddTranslationPath(const std::string& dir,
+                                 const std::string& refdir);
+
+  /**
+   * If dir is different after CollapseFullPath is called,
+   * Then insert it into the path translation table
+   */
+  static void AddKeepPath(const std::string& dir);
+
+  /**
+   * Update path by going through the Path Translation table;
+   */
+  static void CheckTranslationPath(std::string& path);
+
+  /**
+   * Delay the execution for a specified amount of time specified
+   * in miliseconds
+   */
+  static void Delay(unsigned int msec);
+
+  /**
+   * Get the operating system name and version
+   * This is implemented for Win32 only for the moment
+   */
+  static std::string GetOperatingSystemNameAndVersion();
+
+  /** -----------------------------------------------------------------
+   *               URL Manipulation Routines
+   *  -----------------------------------------------------------------
+   */
+
+  /**
+   * Parse a character string :
+   *       protocol://dataglom
+   * and fill protocol as appropriate.
+   * Return false if the URL does not have the required form, true otherwise.
+   */
+  static bool ParseURLProtocol(const std::string& URL, std::string& protocol,
+                               std::string& dataglom);
+
+  /**
+   * Parse a string (a URL without protocol prefix) with the form:
+   *  protocol://[[username[':'password]'@']hostname[':'dataport]]'/'[datapath]
+   * and fill protocol, username, password, hostname, dataport, and datapath
+   * when values are found.
+   * Return true if the string matches the format; false otherwise.
+   */
+  static bool ParseURL(const std::string& URL, std::string& protocol,
+                       std::string& username, std::string& password,
+                       std::string& hostname, std::string& dataport,
+                       std::string& datapath);
+
+private:
+  /**
+   * Allocate the stl map that serve as the Path Translation table.
+   */
+  static void ClassInitialize();
+
+  /**
+   * Deallocate the stl map that serve as the Path Translation table.
+   */
+  static void ClassFinalize();
+
+  /**
+   * This method prevents warning on SGI
+   */
+  SystemToolsManager* GetSystemToolsManager()
+  {
+    return &SystemToolsManagerInstance;
+  }
+
+  /**
+   * Actual implementation of ReplaceString.
+   */
+  static void ReplaceString(std::string& source, const char* replace,
+                            size_t replaceSize, const std::string& with);
+
+  /**
+   * Actual implementation of FileIsFullPath.
+   */
+  static bool FileIsFullPath(const char*, size_t);
+
+  /**
+   * Find a filename (file or directory) in the system PATH, with
+   * optional extra paths.
+   */
+  static std::string FindName(
+    const std::string& name,
+    const std::vector<std::string>& path = std::vector<std::string>(),
+    bool no_system_path = false);
+
+  static const char* GetEnvImpl(const char* key);
+
+  /**
+   * Path translation table from dir to refdir
+   * Each time 'dir' will be found it will be replace by 'refdir'
+   */
+  static SystemToolsTranslationMap* TranslationMap;
+#ifdef _WIN32
+  static SystemToolsPathCaseMap* PathCaseMap;
+  static SystemToolsEnvMap* EnvMap;
+#endif
+#ifdef __CYGWIN__
+  static SystemToolsTranslationMap* Cyg2Win32Map;
+#endif
+  friend class SystemToolsManager;
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Terminal.c b/thirdparty/KWSys/adios2sys/Terminal.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0b7f454b6dd27e47a0a76fd9b6dff0b95db8f8f
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Terminal.c
@@ -0,0 +1,412 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Terminal.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "Terminal.h.in"
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Configure support for this platform.  */
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define KWSYS_TERMINAL_SUPPORT_CONSOLE
+#endif
+#if !defined(_WIN32)
+#define KWSYS_TERMINAL_ISATTY_WORKS
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Include needed system APIs.  */
+
+#include <stdarg.h> /* va_list */
+#include <stdlib.h> /* getenv */
+#include <string.h> /* strcmp */
+
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+#include <io.h>      /* _get_osfhandle */
+#include <windows.h> /* SetConsoleTextAttribute */
+#endif
+
+#if defined(KWSYS_TERMINAL_ISATTY_WORKS)
+#include <unistd.h> /* isatty */
+#else
+#include <sys/stat.h> /* fstat */
+#endif
+
+/*--------------------------------------------------------------------------*/
+static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100,
+                                      int default_tty);
+static void kwsysTerminalSetVT100Color(FILE* stream, int color);
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+static HANDLE kwsysTerminalGetStreamHandle(FILE* stream);
+static void kwsysTerminalSetConsoleColor(HANDLE hOut,
+                                         CONSOLE_SCREEN_BUFFER_INFO* hOutInfo,
+                                         FILE* stream, int color);
+#endif
+
+/*--------------------------------------------------------------------------*/
+void kwsysTerminal_cfprintf(int color, FILE* stream, const char* format, ...)
+{
+  /* Setup the stream with the given color if possible.  */
+  int pipeIsConsole = 0;
+  int pipeIsVT100 = 0;
+  int default_vt100 = color & kwsysTerminal_Color_AssumeVT100;
+  int default_tty = color & kwsysTerminal_Color_AssumeTTY;
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+  CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
+  HANDLE hOut = kwsysTerminalGetStreamHandle(stream);
+  if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) {
+    pipeIsConsole = 1;
+    kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, color);
+  }
+#endif
+  if (!pipeIsConsole &&
+      kwsysTerminalStreamIsVT100(stream, default_vt100, default_tty)) {
+    pipeIsVT100 = 1;
+    kwsysTerminalSetVT100Color(stream, color);
+  }
+
+  /* Format the text into the stream.  */
+  {
+    va_list var_args;
+    va_start(var_args, format);
+    vfprintf(stream, format, var_args);
+    va_end(var_args);
+  }
+
+/* Restore the normal color state for the stream.  */
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+  if (pipeIsConsole) {
+    kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream,
+                                 kwsysTerminal_Color_Normal);
+  }
+#endif
+  if (pipeIsVT100) {
+    kwsysTerminalSetVT100Color(stream, kwsysTerminal_Color_Normal);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Detect cases when a stream is definitely not interactive.  */
+#if !defined(KWSYS_TERMINAL_ISATTY_WORKS)
+static int kwsysTerminalStreamIsNotInteractive(FILE* stream)
+{
+  /* The given stream is definitely not interactive if it is a regular
+     file.  */
+  struct stat stream_stat;
+  if (fstat(fileno(stream), &stream_stat) == 0) {
+    if (stream_stat.st_mode & S_IFREG) {
+      return 1;
+    }
+  }
+  return 0;
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* List of terminal names known to support VT100 color escape sequences.  */
+static const char* kwsysTerminalVT100Names[] = { "Eterm",
+                                                 "ansi",
+                                                 "color-xterm",
+                                                 "con132x25",
+                                                 "con132x30",
+                                                 "con132x43",
+                                                 "con132x60",
+                                                 "con80x25",
+                                                 "con80x28",
+                                                 "con80x30",
+                                                 "con80x43",
+                                                 "con80x50",
+                                                 "con80x60",
+                                                 "cons25",
+                                                 "console",
+                                                 "cygwin",
+                                                 "dtterm",
+                                                 "eterm-color",
+                                                 "gnome",
+                                                 "gnome-256color",
+                                                 "konsole",
+                                                 "konsole-256color",
+                                                 "kterm",
+                                                 "linux",
+                                                 "msys",
+                                                 "linux-c",
+                                                 "mach-color",
+                                                 "mlterm",
+                                                 "putty",
+                                                 "putty-256color",
+                                                 "rxvt",
+                                                 "rxvt-256color",
+                                                 "rxvt-cygwin",
+                                                 "rxvt-cygwin-native",
+                                                 "rxvt-unicode",
+                                                 "rxvt-unicode-256color",
+                                                 "screen",
+                                                 "screen-256color",
+                                                 "screen-256color-bce",
+                                                 "screen-bce",
+                                                 "screen-w",
+                                                 "screen.linux",
+                                                 "tmux",
+                                                 "tmux-256color",
+                                                 "vt100",
+                                                 "xterm",
+                                                 "xterm-16color",
+                                                 "xterm-256color",
+                                                 "xterm-88color",
+                                                 "xterm-color",
+                                                 "xterm-debian",
+                                                 "xterm-termite",
+                                                 0 };
+
+/*--------------------------------------------------------------------------*/
+/* Detect whether a stream is displayed in a VT100-compatible terminal.  */
+static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100,
+                                      int default_tty)
+{
+  /* Force color according to http://bixense.com/clicolors/ convention.  */
+  {
+    const char* clicolor_force = getenv("CLICOLOR_FORCE");
+    if (clicolor_force && *clicolor_force &&
+        strcmp(clicolor_force, "0") != 0) {
+      return 1;
+    }
+  }
+
+  /* If running inside emacs the terminal is not VT100.  Some emacs
+     seem to claim the TERM is xterm even though they do not support
+     VT100 escapes.  */
+  {
+    const char* emacs = getenv("EMACS");
+    if (emacs && *emacs == 't') {
+      return 0;
+    }
+  }
+
+  /* Check for a valid terminal.  */
+  if (!default_vt100) {
+    const char** t = 0;
+    const char* term = getenv("TERM");
+    if (term) {
+      for (t = kwsysTerminalVT100Names; *t && strcmp(term, *t) != 0; ++t) {
+      }
+    }
+    if (!(t && *t)) {
+      return 0;
+    }
+  }
+
+#if defined(KWSYS_TERMINAL_ISATTY_WORKS)
+  /* Make sure the stream is a tty. */
+  (void)default_tty;
+  return isatty(fileno(stream)) ? 1 : 0;
+#else
+  /* Check for cases in which the stream is definitely not a tty.  */
+  if (kwsysTerminalStreamIsNotInteractive(stream)) {
+    return 0;
+  }
+
+  /* Use the provided default for whether this is a tty.  */
+  return default_tty;
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+/* VT100 escape sequence strings.  */
+#define KWSYS_TERMINAL_VT100_NORMAL "\33[0m"
+#define KWSYS_TERMINAL_VT100_BOLD "\33[1m"
+#define KWSYS_TERMINAL_VT100_UNDERLINE "\33[4m"
+#define KWSYS_TERMINAL_VT100_BLINK "\33[5m"
+#define KWSYS_TERMINAL_VT100_INVERSE "\33[7m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_BLACK "\33[30m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_RED "\33[31m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_GREEN "\33[32m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW "\33[33m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_BLUE "\33[34m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA "\33[35m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_CYAN "\33[36m"
+#define KWSYS_TERMINAL_VT100_FOREGROUND_WHITE "\33[37m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_BLACK "\33[40m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_RED "\33[41m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_GREEN "\33[42m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW "\33[43m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_BLUE "\33[44m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA "\33[45m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_CYAN "\33[46m"
+#define KWSYS_TERMINAL_VT100_BACKGROUND_WHITE "\33[47m"
+
+/*--------------------------------------------------------------------------*/
+/* Write VT100 escape sequences to the stream for the given color.  */
+static void kwsysTerminalSetVT100Color(FILE* stream, int color)
+{
+  if (color == kwsysTerminal_Color_Normal) {
+    fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL);
+    return;
+  }
+
+  switch (color & kwsysTerminal_Color_ForegroundMask) {
+    case kwsysTerminal_Color_Normal:
+      fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL);
+      break;
+    case kwsysTerminal_Color_ForegroundBlack:
+      fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLACK);
+      break;
+    case kwsysTerminal_Color_ForegroundRed:
+      fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_RED);
+      break;
+    case kwsysTerminal_Color_ForegroundGreen:
+      fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_GREEN);
+      break;
+    case kwsysTerminal_Color_ForegroundYellow:
+      fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW);
+      break;
+    case kwsysTerminal_Color_ForegroundBlue:
+      fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLUE);
+      break;
+    case kwsysTerminal_Color_ForegroundMagenta:
+      fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA);
+      break;
+    case kwsysTerminal_Color_ForegroundCyan:
+      fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_CYAN);
+      break;
+    case kwsysTerminal_Color_ForegroundWhite:
+      fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_WHITE);
+      break;
+  }
+  switch (color & kwsysTerminal_Color_BackgroundMask) {
+    case kwsysTerminal_Color_BackgroundBlack:
+      fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLACK);
+      break;
+    case kwsysTerminal_Color_BackgroundRed:
+      fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_RED);
+      break;
+    case kwsysTerminal_Color_BackgroundGreen:
+      fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_GREEN);
+      break;
+    case kwsysTerminal_Color_BackgroundYellow:
+      fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW);
+      break;
+    case kwsysTerminal_Color_BackgroundBlue:
+      fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLUE);
+      break;
+    case kwsysTerminal_Color_BackgroundMagenta:
+      fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA);
+      break;
+    case kwsysTerminal_Color_BackgroundCyan:
+      fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_CYAN);
+      break;
+    case kwsysTerminal_Color_BackgroundWhite:
+      fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_WHITE);
+      break;
+  }
+  if (color & kwsysTerminal_Color_ForegroundBold) {
+    fprintf(stream, KWSYS_TERMINAL_VT100_BOLD);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+
+#define KWSYS_TERMINAL_MASK_FOREGROUND                                        \
+  (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
+#define KWSYS_TERMINAL_MASK_BACKGROUND                                        \
+  (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
+
+/* Get the Windows handle for a FILE stream.  */
+static HANDLE kwsysTerminalGetStreamHandle(FILE* stream)
+{
+  /* Get the C-library file descriptor from the stream.  */
+  int fd = fileno(stream);
+
+#if defined(__CYGWIN__)
+  /* Cygwin seems to have an extra pipe level.  If the file descriptor
+     corresponds to stdout or stderr then obtain the matching windows
+     handle directly.  */
+  if (fd == fileno(stdout)) {
+    return GetStdHandle(STD_OUTPUT_HANDLE);
+  } else if (fd == fileno(stderr)) {
+    return GetStdHandle(STD_ERROR_HANDLE);
+  }
+#endif
+
+  /* Get the underlying Windows handle for the descriptor.  */
+  return (HANDLE)_get_osfhandle(fd);
+}
+
+/* Set color attributes in a Windows console.  */
+static void kwsysTerminalSetConsoleColor(HANDLE hOut,
+                                         CONSOLE_SCREEN_BUFFER_INFO* hOutInfo,
+                                         FILE* stream, int color)
+{
+  WORD attributes = 0;
+  switch (color & kwsysTerminal_Color_ForegroundMask) {
+    case kwsysTerminal_Color_Normal:
+      attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_FOREGROUND;
+      break;
+    case kwsysTerminal_Color_ForegroundBlack:
+      attributes |= 0;
+      break;
+    case kwsysTerminal_Color_ForegroundRed:
+      attributes |= FOREGROUND_RED;
+      break;
+    case kwsysTerminal_Color_ForegroundGreen:
+      attributes |= FOREGROUND_GREEN;
+      break;
+    case kwsysTerminal_Color_ForegroundYellow:
+      attributes |= FOREGROUND_RED | FOREGROUND_GREEN;
+      break;
+    case kwsysTerminal_Color_ForegroundBlue:
+      attributes |= FOREGROUND_BLUE;
+      break;
+    case kwsysTerminal_Color_ForegroundMagenta:
+      attributes |= FOREGROUND_RED | FOREGROUND_BLUE;
+      break;
+    case kwsysTerminal_Color_ForegroundCyan:
+      attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN;
+      break;
+    case kwsysTerminal_Color_ForegroundWhite:
+      attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
+      break;
+  }
+  switch (color & kwsysTerminal_Color_BackgroundMask) {
+    case kwsysTerminal_Color_Normal:
+      attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_BACKGROUND;
+      break;
+    case kwsysTerminal_Color_BackgroundBlack:
+      attributes |= 0;
+      break;
+    case kwsysTerminal_Color_BackgroundRed:
+      attributes |= BACKGROUND_RED;
+      break;
+    case kwsysTerminal_Color_BackgroundGreen:
+      attributes |= BACKGROUND_GREEN;
+      break;
+    case kwsysTerminal_Color_BackgroundYellow:
+      attributes |= BACKGROUND_RED | BACKGROUND_GREEN;
+      break;
+    case kwsysTerminal_Color_BackgroundBlue:
+      attributes |= BACKGROUND_BLUE;
+      break;
+    case kwsysTerminal_Color_BackgroundMagenta:
+      attributes |= BACKGROUND_RED | BACKGROUND_BLUE;
+      break;
+    case kwsysTerminal_Color_BackgroundCyan:
+      attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN;
+      break;
+    case kwsysTerminal_Color_BackgroundWhite:
+      attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
+      break;
+  }
+  if (color & kwsysTerminal_Color_ForegroundBold) {
+    attributes |= FOREGROUND_INTENSITY;
+  }
+  if (color & kwsysTerminal_Color_BackgroundBold) {
+    attributes |= BACKGROUND_INTENSITY;
+  }
+  fflush(stream);
+  SetConsoleTextAttribute(hOut, attributes);
+}
+#endif
diff --git a/thirdparty/KWSys/adios2sys/Terminal.h.in b/thirdparty/KWSys/adios2sys/Terminal.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..5d298300422b73c019623a3171fa843f9716eaef
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/Terminal.h.in
@@ -0,0 +1,170 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Terminal_h
+#define @KWSYS_NAMESPACE@_Terminal_h
+
+#include <@KWSYS_NAMESPACE@/Configure.h>
+
+#include <stdio.h> /* For file stream type FILE. */
+
+/* Redefine all public interface symbol names to be in the proper
+   namespace.  These macros are used internally to kwsys only, and are
+   not visible to user code.  Use kwsysHeaderDump.pl to reproduce
+   these macros after making changes to the interface.  */
+#if !defined(KWSYS_NAMESPACE)
+#define kwsys_ns(x) @KWSYS_NAMESPACE@##x
+#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+#endif
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#define kwsysTerminal_cfprintf kwsys_ns(Terminal_cfprintf)
+#define kwsysTerminal_Color_e kwsys_ns(Terminal_Color_e)
+#define kwsysTerminal_Color_Normal kwsys_ns(Terminal_Color_Normal)
+#define kwsysTerminal_Color_ForegroundBlack                                   \
+  kwsys_ns(Terminal_Color_ForegroundBlack)
+#define kwsysTerminal_Color_ForegroundRed                                     \
+  kwsys_ns(Terminal_Color_ForegroundRed)
+#define kwsysTerminal_Color_ForegroundGreen                                   \
+  kwsys_ns(Terminal_Color_ForegroundGreen)
+#define kwsysTerminal_Color_ForegroundYellow                                  \
+  kwsys_ns(Terminal_Color_ForegroundYellow)
+#define kwsysTerminal_Color_ForegroundBlue                                    \
+  kwsys_ns(Terminal_Color_ForegroundBlue)
+#define kwsysTerminal_Color_ForegroundMagenta                                 \
+  kwsys_ns(Terminal_Color_ForegroundMagenta)
+#define kwsysTerminal_Color_ForegroundCyan                                    \
+  kwsys_ns(Terminal_Color_ForegroundCyan)
+#define kwsysTerminal_Color_ForegroundWhite                                   \
+  kwsys_ns(Terminal_Color_ForegroundWhite)
+#define kwsysTerminal_Color_ForegroundMask                                    \
+  kwsys_ns(Terminal_Color_ForegroundMask)
+#define kwsysTerminal_Color_BackgroundBlack                                   \
+  kwsys_ns(Terminal_Color_BackgroundBlack)
+#define kwsysTerminal_Color_BackgroundRed                                     \
+  kwsys_ns(Terminal_Color_BackgroundRed)
+#define kwsysTerminal_Color_BackgroundGreen                                   \
+  kwsys_ns(Terminal_Color_BackgroundGreen)
+#define kwsysTerminal_Color_BackgroundYellow                                  \
+  kwsys_ns(Terminal_Color_BackgroundYellow)
+#define kwsysTerminal_Color_BackgroundBlue                                    \
+  kwsys_ns(Terminal_Color_BackgroundBlue)
+#define kwsysTerminal_Color_BackgroundMagenta                                 \
+  kwsys_ns(Terminal_Color_BackgroundMagenta)
+#define kwsysTerminal_Color_BackgroundCyan                                    \
+  kwsys_ns(Terminal_Color_BackgroundCyan)
+#define kwsysTerminal_Color_BackgroundWhite                                   \
+  kwsys_ns(Terminal_Color_BackgroundWhite)
+#define kwsysTerminal_Color_BackgroundMask                                    \
+  kwsys_ns(Terminal_Color_BackgroundMask)
+#define kwsysTerminal_Color_ForegroundBold                                    \
+  kwsys_ns(Terminal_Color_ForegroundBold)
+#define kwsysTerminal_Color_BackgroundBold                                    \
+  kwsys_ns(Terminal_Color_BackgroundBold)
+#define kwsysTerminal_Color_AssumeTTY kwsys_ns(Terminal_Color_AssumeTTY)
+#define kwsysTerminal_Color_AssumeVT100 kwsys_ns(Terminal_Color_AssumeVT100)
+#define kwsysTerminal_Color_AttributeMask                                     \
+  kwsys_ns(Terminal_Color_AttributeMask)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Write colored and formatted text to a stream.  Color is used only
+ * for streams supporting it.  The color specification is constructed
+ * by bitwise-OR-ing enumeration values.  At most one foreground and
+ * one background value may be given.
+ *
+ * Whether the a stream supports color is usually automatically
+ * detected, but with two exceptions:
+ *
+ *   - When the stream is displayed in a terminal supporting VT100
+ *   color but using an intermediate pipe for communication the
+ *   detection of a tty fails.  (This typically occurs for a shell
+ *   running in an rxvt terminal in MSYS.)  If the caller knows this
+ *   to be the case, the attribute Color_AssumeTTY may be included in
+ *   the color specification.
+ *
+ *   - When the stream is displayed in a terminal whose TERM
+ *   environment variable is not set or is set to a value that is not
+ *   known to support VT100 colors.  If the caller knows this to be
+ *   the case, the attribute Color_AssumeVT100 may be included in the
+ *   color specification.
+ */
+kwsysEXPORT void kwsysTerminal_cfprintf(int color, FILE* stream,
+                                        const char* format, ...);
+enum kwsysTerminal_Color_e
+{
+  /* Normal Text */
+  kwsysTerminal_Color_Normal = 0,
+
+  /* Foreground Color */
+  kwsysTerminal_Color_ForegroundBlack = 0x1,
+  kwsysTerminal_Color_ForegroundRed = 0x2,
+  kwsysTerminal_Color_ForegroundGreen = 0x3,
+  kwsysTerminal_Color_ForegroundYellow = 0x4,
+  kwsysTerminal_Color_ForegroundBlue = 0x5,
+  kwsysTerminal_Color_ForegroundMagenta = 0x6,
+  kwsysTerminal_Color_ForegroundCyan = 0x7,
+  kwsysTerminal_Color_ForegroundWhite = 0x8,
+  kwsysTerminal_Color_ForegroundMask = 0xF,
+
+  /* Background Color */
+  kwsysTerminal_Color_BackgroundBlack = 0x10,
+  kwsysTerminal_Color_BackgroundRed = 0x20,
+  kwsysTerminal_Color_BackgroundGreen = 0x30,
+  kwsysTerminal_Color_BackgroundYellow = 0x40,
+  kwsysTerminal_Color_BackgroundBlue = 0x50,
+  kwsysTerminal_Color_BackgroundMagenta = 0x60,
+  kwsysTerminal_Color_BackgroundCyan = 0x70,
+  kwsysTerminal_Color_BackgroundWhite = 0x80,
+  kwsysTerminal_Color_BackgroundMask = 0xF0,
+
+  /* Attributes */
+  kwsysTerminal_Color_ForegroundBold = 0x100,
+  kwsysTerminal_Color_BackgroundBold = 0x200,
+  kwsysTerminal_Color_AssumeTTY = 0x400,
+  kwsysTerminal_Color_AssumeVT100 = 0x800,
+  kwsysTerminal_Color_AttributeMask = 0xF00
+};
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+/* If we are building a kwsys .c or .cxx file, let it use these macros.
+   Otherwise, undefine them to keep the namespace clean.  */
+#if !defined(KWSYS_NAMESPACE)
+#undef kwsys_ns
+#undef kwsysEXPORT
+#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#undef kwsysTerminal_cfprintf
+#undef kwsysTerminal_Color_e
+#undef kwsysTerminal_Color_Normal
+#undef kwsysTerminal_Color_ForegroundBlack
+#undef kwsysTerminal_Color_ForegroundRed
+#undef kwsysTerminal_Color_ForegroundGreen
+#undef kwsysTerminal_Color_ForegroundYellow
+#undef kwsysTerminal_Color_ForegroundBlue
+#undef kwsysTerminal_Color_ForegroundMagenta
+#undef kwsysTerminal_Color_ForegroundCyan
+#undef kwsysTerminal_Color_ForegroundWhite
+#undef kwsysTerminal_Color_ForegroundMask
+#undef kwsysTerminal_Color_BackgroundBlack
+#undef kwsysTerminal_Color_BackgroundRed
+#undef kwsysTerminal_Color_BackgroundGreen
+#undef kwsysTerminal_Color_BackgroundYellow
+#undef kwsysTerminal_Color_BackgroundBlue
+#undef kwsysTerminal_Color_BackgroundMagenta
+#undef kwsysTerminal_Color_BackgroundCyan
+#undef kwsysTerminal_Color_BackgroundWhite
+#undef kwsysTerminal_Color_BackgroundMask
+#undef kwsysTerminal_Color_ForegroundBold
+#undef kwsysTerminal_Color_BackgroundBold
+#undef kwsysTerminal_Color_AssumeTTY
+#undef kwsysTerminal_Color_AssumeVT100
+#undef kwsysTerminal_Color_AttributeMask
+#endif
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/hash_fun.hxx.in b/thirdparty/KWSys/adios2sys/hash_fun.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..8626c2aa2a19712bea58e63b6e5b781ccd372c22
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/hash_fun.hxx.in
@@ -0,0 +1,166 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+/*
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifndef @KWSYS_NAMESPACE@_hash_fun_hxx
+#define @KWSYS_NAMESPACE@_hash_fun_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <stddef.h> // size_t
+#include <string>
+
+namespace @KWSYS_NAMESPACE@ {
+
+template <class _Key>
+struct hash
+{
+};
+
+inline size_t _stl_hash_string(const char* __s)
+{
+  unsigned long __h = 0;
+  for (; *__s; ++__s)
+    __h = 5 * __h + *__s;
+
+  return size_t(__h);
+}
+
+template <>
+struct hash<char*>
+{
+  size_t operator()(const char* __s) const { return _stl_hash_string(__s); }
+};
+
+template <>
+struct hash<const char*>
+{
+  size_t operator()(const char* __s) const { return _stl_hash_string(__s); }
+};
+
+template <>
+struct hash<std::string>
+{
+  size_t operator()(const std::string& __s) const
+  {
+    return _stl_hash_string(__s.c_str());
+  }
+};
+
+#if !defined(__BORLANDC__)
+template <>
+struct hash<const std::string>
+{
+  size_t operator()(const std::string& __s) const
+  {
+    return _stl_hash_string(__s.c_str());
+  }
+};
+#endif
+
+template <>
+struct hash<char>
+{
+  size_t operator()(char __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned char>
+{
+  size_t operator()(unsigned char __x) const { return __x; }
+};
+
+template <>
+struct hash<signed char>
+{
+  size_t operator()(unsigned char __x) const { return __x; }
+};
+
+template <>
+struct hash<short>
+{
+  size_t operator()(short __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned short>
+{
+  size_t operator()(unsigned short __x) const { return __x; }
+};
+
+template <>
+struct hash<int>
+{
+  size_t operator()(int __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned int>
+{
+  size_t operator()(unsigned int __x) const { return __x; }
+};
+
+template <>
+struct hash<long>
+{
+  size_t operator()(long __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned long>
+{
+  size_t operator()(unsigned long __x) const { return __x; }
+};
+
+// use long long or __int64
+#if @KWSYS_USE_LONG_LONG@
+template <>
+struct hash<long long>
+{
+  size_t operator()(long long __x) const { return __x; }
+};
+
+template <>
+struct hash<unsigned long long>
+{
+  size_t operator()(unsigned long long __x) const { return __x; }
+};
+#elif @KWSYS_USE___INT64@
+template <>
+struct hash<__int64>
+{
+  size_t operator()(__int64 __x) const { return __x; }
+};
+template <>
+struct hash<unsigned __int64>
+{
+  size_t operator()(unsigned __int64 __x) const { return __x; }
+};
+#endif // use long long or __int64
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/hash_map.hxx.in b/thirdparty/KWSys/adios2sys/hash_map.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..3f9174f3be7c8d2c06c64ca9f74330468ed35405
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/hash_map.hxx.in
@@ -0,0 +1,423 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+/*
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifndef @KWSYS_NAMESPACE@_hash_map_hxx
+#define @KWSYS_NAMESPACE@_hash_map_hxx
+
+#include <@KWSYS_NAMESPACE@/hashtable.hxx>
+
+#include <@KWSYS_NAMESPACE@/hash_fun.hxx>
+
+#include <functional> // equal_to
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4284)
+#pragma warning(disable : 4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+#pragma set woff 1174
+#pragma set woff 1375
+#endif
+
+namespace @KWSYS_NAMESPACE@ {
+
+// select1st is an extension: it is not part of the standard.
+template <class T1, class T2>
+struct hash_select1st : public std::unary_function<std::pair<T1, T2>, T1>
+{
+  const T1& operator()(const std::pair<T1, T2>& __x) const
+  {
+    return __x.first;
+  }
+};
+
+// Forward declaration of equality operator; needed for friend declaration.
+
+template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
+          class _EqualKey = std::equal_to<_Key>,
+          class _Alloc = std::allocator<char> >
+class hash_map;
+
+template <class _Key, class _Tp, class _HashFn, class _EqKey, class _Alloc>
+bool operator==(const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&,
+                const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&);
+
+template <class _Key, class _Tp, class _HashFcn, class _EqualKey, class _Alloc>
+class hash_map
+{
+private:
+  typedef hashtable<std::pair<const _Key, _Tp>, _Key, _HashFcn,
+                    hash_select1st<const _Key, _Tp>, _EqualKey, _Alloc>
+    _Ht;
+  _Ht _M_ht;
+
+public:
+  typedef typename _Ht::key_type key_type;
+  typedef _Tp data_type;
+  typedef _Tp mapped_type;
+  typedef typename _Ht::value_type value_type;
+  typedef typename _Ht::hasher hasher;
+  typedef typename _Ht::key_equal key_equal;
+
+  typedef typename _Ht::size_type size_type;
+  typedef typename _Ht::difference_type difference_type;
+  typedef typename _Ht::pointer pointer;
+  typedef typename _Ht::const_pointer const_pointer;
+  typedef typename _Ht::reference reference;
+  typedef typename _Ht::const_reference const_reference;
+
+  typedef typename _Ht::iterator iterator;
+  typedef typename _Ht::const_iterator const_iterator;
+
+  typedef typename _Ht::allocator_type allocator_type;
+
+  hasher hash_funct() const { return _M_ht.hash_funct(); }
+  key_equal key_eq() const { return _M_ht.key_eq(); }
+  allocator_type get_allocator() const { return _M_ht.get_allocator(); }
+
+public:
+  hash_map()
+    : _M_ht(100, hasher(), key_equal(), allocator_type())
+  {
+  }
+  explicit hash_map(size_type __n)
+    : _M_ht(__n, hasher(), key_equal(), allocator_type())
+  {
+  }
+  hash_map(size_type __n, const hasher& __hf)
+    : _M_ht(__n, __hf, key_equal(), allocator_type())
+  {
+  }
+  hash_map(size_type __n, const hasher& __hf, const key_equal& __eql,
+           const allocator_type& __a = allocator_type())
+    : _M_ht(__n, __hf, __eql, __a)
+  {
+  }
+
+  template <class _InputIterator>
+  hash_map(_InputIterator __f, _InputIterator __l)
+    : _M_ht(100, hasher(), key_equal(), allocator_type())
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_map(_InputIterator __f, _InputIterator __l, size_type __n)
+    : _M_ht(__n, hasher(), key_equal(), allocator_type())
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_map(_InputIterator __f, _InputIterator __l, size_type __n,
+           const hasher& __hf)
+    : _M_ht(__n, __hf, key_equal(), allocator_type())
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_map(_InputIterator __f, _InputIterator __l, size_type __n,
+           const hasher& __hf, const key_equal& __eql,
+           const allocator_type& __a = allocator_type())
+    : _M_ht(__n, __hf, __eql, __a)
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+
+public:
+  size_type size() const { return _M_ht.size(); }
+  size_type max_size() const { return _M_ht.max_size(); }
+  bool empty() const { return _M_ht.empty(); }
+  void swap(hash_map& __hs) { _M_ht.swap(__hs._M_ht); }
+
+  friend bool operator==<>(const hash_map&, const hash_map&);
+
+  iterator begin() { return _M_ht.begin(); }
+  iterator end() { return _M_ht.end(); }
+  const_iterator begin() const { return _M_ht.begin(); }
+  const_iterator end() const { return _M_ht.end(); }
+
+public:
+  std::pair<iterator, bool> insert(const value_type& __obj)
+  {
+    return _M_ht.insert_unique(__obj);
+  }
+  template <class _InputIterator>
+  void insert(_InputIterator __f, _InputIterator __l)
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+  std::pair<iterator, bool> insert_noresize(const value_type& __obj)
+  {
+    return _M_ht.insert_unique_noresize(__obj);
+  }
+
+  iterator find(const key_type& __key) { return _M_ht.find(__key); }
+  const_iterator find(const key_type& __key) const
+  {
+    return _M_ht.find(__key);
+  }
+
+  _Tp& operator[](const key_type& __key)
+  {
+    return _M_ht.find_or_insert(value_type(__key, _Tp())).second;
+  }
+
+  size_type count(const key_type& __key) const { return _M_ht.count(__key); }
+
+  std::pair<iterator, iterator> equal_range(const key_type& __key)
+  {
+    return _M_ht.equal_range(__key);
+  }
+  std::pair<const_iterator, const_iterator> equal_range(
+    const key_type& __key) const
+  {
+    return _M_ht.equal_range(__key);
+  }
+
+  size_type erase(const key_type& __key) { return _M_ht.erase(__key); }
+  void erase(iterator __it) { _M_ht.erase(__it); }
+  void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
+  void clear() { _M_ht.clear(); }
+
+  void resize(size_type __hint) { _M_ht.resize(__hint); }
+  size_type bucket_count() const { return _M_ht.bucket_count(); }
+  size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
+  size_type elems_in_bucket(size_type __n) const
+  {
+    return _M_ht.elems_in_bucket(__n);
+  }
+};
+
+template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
+bool operator==(const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1,
+                const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2)
+{
+  return __hm1._M_ht == __hm2._M_ht;
+}
+
+template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
+inline bool operator!=(
+  const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1,
+  const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2)
+{
+  return !(__hm1 == __hm2);
+}
+
+template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
+inline void swap(hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1,
+                 hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2)
+{
+  __hm1.swap(__hm2);
+}
+
+// Forward declaration of equality operator; needed for friend declaration.
+
+template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
+          class _EqualKey = std::equal_to<_Key>,
+          class _Alloc = std::allocator<char> >
+class hash_multimap;
+
+template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
+bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1,
+                const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2);
+
+template <class _Key, class _Tp, class _HashFcn, class _EqualKey, class _Alloc>
+class hash_multimap
+{
+private:
+  typedef hashtable<std::pair<const _Key, _Tp>, _Key, _HashFcn,
+                    hash_select1st<const _Key, _Tp>, _EqualKey, _Alloc>
+    _Ht;
+  _Ht _M_ht;
+
+public:
+  typedef typename _Ht::key_type key_type;
+  typedef _Tp data_type;
+  typedef _Tp mapped_type;
+  typedef typename _Ht::value_type value_type;
+  typedef typename _Ht::hasher hasher;
+  typedef typename _Ht::key_equal key_equal;
+
+  typedef typename _Ht::size_type size_type;
+  typedef typename _Ht::difference_type difference_type;
+  typedef typename _Ht::pointer pointer;
+  typedef typename _Ht::const_pointer const_pointer;
+  typedef typename _Ht::reference reference;
+  typedef typename _Ht::const_reference const_reference;
+
+  typedef typename _Ht::iterator iterator;
+  typedef typename _Ht::const_iterator const_iterator;
+
+  typedef typename _Ht::allocator_type allocator_type;
+
+  hasher hash_funct() const { return _M_ht.hash_funct(); }
+  key_equal key_eq() const { return _M_ht.key_eq(); }
+  allocator_type get_allocator() const { return _M_ht.get_allocator(); }
+
+public:
+  hash_multimap()
+    : _M_ht(100, hasher(), key_equal(), allocator_type())
+  {
+  }
+  explicit hash_multimap(size_type __n)
+    : _M_ht(__n, hasher(), key_equal(), allocator_type())
+  {
+  }
+  hash_multimap(size_type __n, const hasher& __hf)
+    : _M_ht(__n, __hf, key_equal(), allocator_type())
+  {
+  }
+  hash_multimap(size_type __n, const hasher& __hf, const key_equal& __eql,
+                const allocator_type& __a = allocator_type())
+    : _M_ht(__n, __hf, __eql, __a)
+  {
+  }
+
+  template <class _InputIterator>
+  hash_multimap(_InputIterator __f, _InputIterator __l)
+    : _M_ht(100, hasher(), key_equal(), allocator_type())
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n)
+    : _M_ht(__n, hasher(), key_equal(), allocator_type())
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n,
+                const hasher& __hf)
+    : _M_ht(__n, __hf, key_equal(), allocator_type())
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n,
+                const hasher& __hf, const key_equal& __eql,
+                const allocator_type& __a = allocator_type())
+    : _M_ht(__n, __hf, __eql, __a)
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+
+public:
+  size_type size() const { return _M_ht.size(); }
+  size_type max_size() const { return _M_ht.max_size(); }
+  bool empty() const { return _M_ht.empty(); }
+  void swap(hash_multimap& __hs) { _M_ht.swap(__hs._M_ht); }
+
+  friend bool operator==<>(const hash_multimap&, const hash_multimap&);
+
+  iterator begin() { return _M_ht.begin(); }
+  iterator end() { return _M_ht.end(); }
+  const_iterator begin() const { return _M_ht.begin(); }
+  const_iterator end() const { return _M_ht.end(); }
+
+public:
+  iterator insert(const value_type& __obj)
+  {
+    return _M_ht.insert_equal(__obj);
+  }
+  template <class _InputIterator>
+  void insert(_InputIterator __f, _InputIterator __l)
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+  iterator insert_noresize(const value_type& __obj)
+  {
+    return _M_ht.insert_equal_noresize(__obj);
+  }
+
+  iterator find(const key_type& __key) { return _M_ht.find(__key); }
+  const_iterator find(const key_type& __key) const
+  {
+    return _M_ht.find(__key);
+  }
+
+  size_type count(const key_type& __key) const { return _M_ht.count(__key); }
+
+  std::pair<iterator, iterator> equal_range(const key_type& __key)
+  {
+    return _M_ht.equal_range(__key);
+  }
+  std::pair<const_iterator, const_iterator> equal_range(
+    const key_type& __key) const
+  {
+    return _M_ht.equal_range(__key);
+  }
+
+  size_type erase(const key_type& __key) { return _M_ht.erase(__key); }
+  void erase(iterator __it) { _M_ht.erase(__it); }
+  void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
+  void clear() { _M_ht.clear(); }
+
+public:
+  void resize(size_type __hint) { _M_ht.resize(__hint); }
+  size_type bucket_count() const { return _M_ht.bucket_count(); }
+  size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
+  size_type elems_in_bucket(size_type __n) const
+  {
+    return _M_ht.elems_in_bucket(__n);
+  }
+};
+
+template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
+bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1,
+                const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2)
+{
+  return __hm1._M_ht == __hm2._M_ht;
+}
+
+template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
+inline bool operator!=(
+  const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1,
+  const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2)
+{
+  return !(__hm1 == __hm2);
+}
+
+template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
+inline void swap(hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1,
+                 hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2)
+{
+  __hm1.swap(__hm2);
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+#pragma reset woff 1174
+#pragma reset woff 1375
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/hash_set.hxx.in b/thirdparty/KWSys/adios2sys/hash_set.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..e3a0c6c44901ee713ff7136a3dd49369b86cfca9
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/hash_set.hxx.in
@@ -0,0 +1,392 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+/*
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifndef @KWSYS_NAMESPACE@_hash_set_hxx
+#define @KWSYS_NAMESPACE@_hash_set_hxx
+
+#include <@KWSYS_NAMESPACE@/hashtable.hxx>
+
+#include <@KWSYS_NAMESPACE@/hash_fun.hxx>
+
+#include <functional> // equal_to
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4284)
+#pragma warning(disable : 4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+#pragma set woff 1174
+#pragma set woff 1375
+#endif
+
+namespace @KWSYS_NAMESPACE@ {
+
+// identity is an extension: it is not part of the standard.
+template <class _Tp>
+struct _Identity : public std::unary_function<_Tp, _Tp>
+{
+  const _Tp& operator()(const _Tp& __x) const { return __x; }
+};
+
+// Forward declaration of equality operator; needed for friend declaration.
+
+template <class _Value, class _HashFcn = hash<_Value>,
+          class _EqualKey = std::equal_to<_Value>,
+          class _Alloc = std::allocator<char> >
+class hash_set;
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1,
+                const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2);
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+class hash_set
+{
+private:
+  typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey,
+                    _Alloc>
+    _Ht;
+  _Ht _M_ht;
+
+public:
+  typedef typename _Ht::key_type key_type;
+  typedef typename _Ht::value_type value_type;
+  typedef typename _Ht::hasher hasher;
+  typedef typename _Ht::key_equal key_equal;
+
+  typedef typename _Ht::size_type size_type;
+  typedef typename _Ht::difference_type difference_type;
+  typedef typename _Ht::const_pointer pointer;
+  typedef typename _Ht::const_pointer const_pointer;
+  typedef typename _Ht::const_reference reference;
+  typedef typename _Ht::const_reference const_reference;
+
+  typedef typename _Ht::const_iterator iterator;
+  typedef typename _Ht::const_iterator const_iterator;
+
+  typedef typename _Ht::allocator_type allocator_type;
+
+  hasher hash_funct() const { return _M_ht.hash_funct(); }
+  key_equal key_eq() const { return _M_ht.key_eq(); }
+  allocator_type get_allocator() const { return _M_ht.get_allocator(); }
+
+public:
+  hash_set()
+    : _M_ht(100, hasher(), key_equal(), allocator_type())
+  {
+  }
+  explicit hash_set(size_type __n)
+    : _M_ht(__n, hasher(), key_equal(), allocator_type())
+  {
+  }
+  hash_set(size_type __n, const hasher& __hf)
+    : _M_ht(__n, __hf, key_equal(), allocator_type())
+  {
+  }
+  hash_set(size_type __n, const hasher& __hf, const key_equal& __eql,
+           const allocator_type& __a = allocator_type())
+    : _M_ht(__n, __hf, __eql, __a)
+  {
+  }
+
+  template <class _InputIterator>
+  hash_set(_InputIterator __f, _InputIterator __l)
+    : _M_ht(100, hasher(), key_equal(), allocator_type())
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_set(_InputIterator __f, _InputIterator __l, size_type __n)
+    : _M_ht(__n, hasher(), key_equal(), allocator_type())
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_set(_InputIterator __f, _InputIterator __l, size_type __n,
+           const hasher& __hf)
+    : _M_ht(__n, __hf, key_equal(), allocator_type())
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_set(_InputIterator __f, _InputIterator __l, size_type __n,
+           const hasher& __hf, const key_equal& __eql,
+           const allocator_type& __a = allocator_type())
+    : _M_ht(__n, __hf, __eql, __a)
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+
+public:
+  size_type size() const { return _M_ht.size(); }
+  size_type max_size() const { return _M_ht.max_size(); }
+  bool empty() const { return _M_ht.empty(); }
+  void swap(hash_set& __hs) { _M_ht.swap(__hs._M_ht); }
+
+  friend bool operator==<>(const hash_set&, const hash_set&);
+
+  iterator begin() const { return _M_ht.begin(); }
+  iterator end() const { return _M_ht.end(); }
+
+public:
+  std::pair<iterator, bool> insert(const value_type& __obj)
+  {
+    typedef typename _Ht::iterator _Ht_iterator;
+    std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique(__obj);
+    return std::pair<iterator, bool>(__p.first, __p.second);
+  }
+  template <class _InputIterator>
+  void insert(_InputIterator __f, _InputIterator __l)
+  {
+    _M_ht.insert_unique(__f, __l);
+  }
+  std::pair<iterator, bool> insert_noresize(const value_type& __obj)
+  {
+    typedef typename _Ht::iterator _Ht_iterator;
+    std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique_noresize(__obj);
+    return std::pair<iterator, bool>(__p.first, __p.second);
+  }
+
+  iterator find(const key_type& __key) const { return _M_ht.find(__key); }
+
+  size_type count(const key_type& __key) const { return _M_ht.count(__key); }
+
+  std::pair<iterator, iterator> equal_range(const key_type& __key) const
+  {
+    return _M_ht.equal_range(__key);
+  }
+
+  size_type erase(const key_type& __key) { return _M_ht.erase(__key); }
+  void erase(iterator __it) { _M_ht.erase(__it); }
+  void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
+  void clear() { _M_ht.clear(); }
+
+public:
+  void resize(size_type __hint) { _M_ht.resize(__hint); }
+  size_type bucket_count() const { return _M_ht.bucket_count(); }
+  size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
+  size_type elems_in_bucket(size_type __n) const
+  {
+    return _M_ht.elems_in_bucket(__n);
+  }
+};
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1,
+                const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2)
+{
+  return __hs1._M_ht == __hs2._M_ht;
+}
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+inline bool operator!=(
+  const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1,
+  const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2)
+{
+  return !(__hs1 == __hs2);
+}
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+inline void swap(hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
+                 hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2)
+{
+  __hs1.swap(__hs2);
+}
+
+template <class _Value, class _HashFcn = hash<_Value>,
+          class _EqualKey = std::equal_to<_Value>,
+          class _Alloc = std::allocator<char> >
+class hash_multiset;
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
+                const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2);
+
+template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
+class hash_multiset
+{
+private:
+  typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey,
+                    _Alloc>
+    _Ht;
+  _Ht _M_ht;
+
+public:
+  typedef typename _Ht::key_type key_type;
+  typedef typename _Ht::value_type value_type;
+  typedef typename _Ht::hasher hasher;
+  typedef typename _Ht::key_equal key_equal;
+
+  typedef typename _Ht::size_type size_type;
+  typedef typename _Ht::difference_type difference_type;
+  typedef typename _Ht::const_pointer pointer;
+  typedef typename _Ht::const_pointer const_pointer;
+  typedef typename _Ht::const_reference reference;
+  typedef typename _Ht::const_reference const_reference;
+
+  typedef typename _Ht::const_iterator iterator;
+  typedef typename _Ht::const_iterator const_iterator;
+
+  typedef typename _Ht::allocator_type allocator_type;
+
+  hasher hash_funct() const { return _M_ht.hash_funct(); }
+  key_equal key_eq() const { return _M_ht.key_eq(); }
+  allocator_type get_allocator() const { return _M_ht.get_allocator(); }
+
+public:
+  hash_multiset()
+    : _M_ht(100, hasher(), key_equal(), allocator_type())
+  {
+  }
+  explicit hash_multiset(size_type __n)
+    : _M_ht(__n, hasher(), key_equal(), allocator_type())
+  {
+  }
+  hash_multiset(size_type __n, const hasher& __hf)
+    : _M_ht(__n, __hf, key_equal(), allocator_type())
+  {
+  }
+  hash_multiset(size_type __n, const hasher& __hf, const key_equal& __eql,
+                const allocator_type& __a = allocator_type())
+    : _M_ht(__n, __hf, __eql, __a)
+  {
+  }
+
+  template <class _InputIterator>
+  hash_multiset(_InputIterator __f, _InputIterator __l)
+    : _M_ht(100, hasher(), key_equal(), allocator_type())
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n)
+    : _M_ht(__n, hasher(), key_equal(), allocator_type())
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n,
+                const hasher& __hf)
+    : _M_ht(__n, __hf, key_equal(), allocator_type())
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+  template <class _InputIterator>
+  hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n,
+                const hasher& __hf, const key_equal& __eql,
+                const allocator_type& __a = allocator_type())
+    : _M_ht(__n, __hf, __eql, __a)
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+
+public:
+  size_type size() const { return _M_ht.size(); }
+  size_type max_size() const { return _M_ht.max_size(); }
+  bool empty() const { return _M_ht.empty(); }
+  void swap(hash_multiset& hs) { _M_ht.swap(hs._M_ht); }
+
+  friend bool operator==<>(const hash_multiset&, const hash_multiset&);
+
+  iterator begin() const { return _M_ht.begin(); }
+  iterator end() const { return _M_ht.end(); }
+
+public:
+  iterator insert(const value_type& __obj)
+  {
+    return _M_ht.insert_equal(__obj);
+  }
+  template <class _InputIterator>
+  void insert(_InputIterator __f, _InputIterator __l)
+  {
+    _M_ht.insert_equal(__f, __l);
+  }
+  iterator insert_noresize(const value_type& __obj)
+  {
+    return _M_ht.insert_equal_noresize(__obj);
+  }
+
+  iterator find(const key_type& __key) const { return _M_ht.find(__key); }
+
+  size_type count(const key_type& __key) const { return _M_ht.count(__key); }
+
+  std::pair<iterator, iterator> equal_range(const key_type& __key) const
+  {
+    return _M_ht.equal_range(__key);
+  }
+
+  size_type erase(const key_type& __key) { return _M_ht.erase(__key); }
+  void erase(iterator __it) { _M_ht.erase(__it); }
+  void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
+  void clear() { _M_ht.clear(); }
+
+public:
+  void resize(size_type __hint) { _M_ht.resize(__hint); }
+  size_type bucket_count() const { return _M_ht.bucket_count(); }
+  size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
+  size_type elems_in_bucket(size_type __n) const
+  {
+    return _M_ht.elems_in_bucket(__n);
+  }
+};
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
+                const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2)
+{
+  return __hs1._M_ht == __hs2._M_ht;
+}
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+inline bool operator!=(
+  const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
+  const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2)
+{
+  return !(__hs1 == __hs2);
+}
+
+template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
+inline void swap(hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
+                 hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2)
+{
+  __hs1.swap(__hs2);
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+#pragma reset woff 1174
+#pragma reset woff 1375
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/hashtable.hxx.in b/thirdparty/KWSys/adios2sys/hashtable.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..dd92cb9d422adaec91f521bf12f513f13f50efb1
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/hashtable.hxx.in
@@ -0,0 +1,993 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+/*
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifdef __BORLANDC__
+#pragma warn - 8027 /* 'for' not inlined.  */
+#pragma warn - 8026 /* 'exception' not inlined.  */
+#endif
+
+#ifndef @KWSYS_NAMESPACE@_hashtable_hxx
+#define @KWSYS_NAMESPACE@_hashtable_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <algorithm>  // lower_bound
+#include <functional> // unary_function
+#include <iterator>   // iterator_traits
+#include <memory>     // allocator
+#include <stddef.h>   // size_t
+#include <utility>    // pair
+#include <vector>     // vector
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4284)
+#pragma warning(disable : 4786)
+#pragma warning(disable : 4512) /* no assignment operator for class */
+#endif
+#if defined(__sgi) && !defined(__GNUC__)
+#pragma set woff 3970 /* pointer to int conversion */ 3321 3968
+#endif
+
+// In C++11, clang will warn about using dynamic exception specifications
+// as they are deprecated.  But as this class is trying to faithfully
+// mimic unordered_set and unordered_map, we want to keep the 'throw()'
+// decorations below.  So we suppress the warning.
+#if defined(__clang__) && defined(__has_warning)
+#if __has_warning("-Wdeprecated")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
+#endif
+#endif
+
+namespace @KWSYS_NAMESPACE@ {
+
+template <class _Val>
+struct _Hashtable_node
+{
+  _Hashtable_node* _M_next;
+  _Val _M_val;
+  void public_method_to_quiet_warning_about_all_methods_private();
+
+private:
+  void operator=(_Hashtable_node<_Val> const&); // poison node assignment
+};
+
+template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
+          class _EqualKey, class _Alloc = std::allocator<char> >
+class hashtable;
+
+template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
+          class _EqualKey, class _Alloc>
+struct _Hashtable_iterator;
+
+template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
+          class _EqualKey, class _Alloc>
+struct _Hashtable_const_iterator;
+
+template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
+          class _EqualKey, class _Alloc>
+struct _Hashtable_iterator
+{
+  typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>
+    _Hashtable;
+  typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey,
+                              _Alloc>
+    iterator;
+  typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
+                                    _EqualKey, _Alloc>
+    const_iterator;
+  typedef _Hashtable_node<_Val> _Node;
+
+  typedef std::forward_iterator_tag iterator_category;
+  typedef _Val value_type;
+  typedef ptrdiff_t difference_type;
+  typedef size_t size_type;
+  typedef _Val& reference;
+  typedef _Val* pointer;
+
+  _Node* _M_cur;
+  _Hashtable* _M_ht;
+
+  _Hashtable_iterator(_Node* __n, _Hashtable* __tab)
+    : _M_cur(__n)
+    , _M_ht(__tab)
+  {
+  }
+  _Hashtable_iterator() {}
+  reference operator*() const { return _M_cur->_M_val; }
+  pointer operator->() const { return &(operator*()); }
+  iterator& operator++();
+  iterator operator++(int);
+  bool operator==(const iterator& __it) const { return _M_cur == __it._M_cur; }
+  bool operator!=(const iterator& __it) const { return _M_cur != __it._M_cur; }
+};
+
+template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
+          class _EqualKey, class _Alloc>
+struct _Hashtable_const_iterator
+{
+  typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>
+    _Hashtable;
+  typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey,
+                              _Alloc>
+    iterator;
+  typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
+                                    _EqualKey, _Alloc>
+    const_iterator;
+  typedef _Hashtable_node<_Val> _Node;
+
+  typedef std::forward_iterator_tag iterator_category;
+  typedef _Val value_type;
+  typedef ptrdiff_t difference_type;
+  typedef size_t size_type;
+  typedef const _Val& reference;
+  typedef const _Val* pointer;
+
+  const _Node* _M_cur;
+  const _Hashtable* _M_ht;
+
+  _Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab)
+    : _M_cur(__n)
+    , _M_ht(__tab)
+  {
+  }
+  _Hashtable_const_iterator() {}
+  _Hashtable_const_iterator(const iterator& __it)
+    : _M_cur(__it._M_cur)
+    , _M_ht(__it._M_ht)
+  {
+  }
+  reference operator*() const { return _M_cur->_M_val; }
+  pointer operator->() const { return &(operator*()); }
+  const_iterator& operator++();
+  const_iterator operator++(int);
+  bool operator==(const const_iterator& __it) const
+  {
+    return _M_cur == __it._M_cur;
+  }
+  bool operator!=(const const_iterator& __it) const
+  {
+    return _M_cur != __it._M_cur;
+  }
+};
+
+// Note: assumes long is at least 32 bits.
+enum
+{
+  _stl_num_primes = 31
+};
+
+// create a function with a static local to that function that returns
+// the static
+static inline const unsigned long* get_stl_prime_list()
+{
+
+  static const unsigned long _stl_prime_list[_stl_num_primes] = {
+    5ul,         11ul,        23ul,        53ul,         97ul,
+    193ul,       389ul,       769ul,       1543ul,       3079ul,
+    6151ul,      12289ul,     24593ul,     49157ul,      98317ul,
+    196613ul,    393241ul,    786433ul,    1572869ul,    3145739ul,
+    6291469ul,   12582917ul,  25165843ul,  50331653ul,   100663319ul,
+    201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul,
+    4294967291ul
+  };
+
+  return &_stl_prime_list[0];
+}
+
+static inline size_t _stl_next_prime(size_t __n)
+{
+  const unsigned long* __first = get_stl_prime_list();
+  const unsigned long* __last = get_stl_prime_list() + (int)_stl_num_primes;
+  const unsigned long* pos = std::lower_bound(__first, __last, __n);
+  return pos == __last ? *(__last - 1) : *pos;
+}
+
+// Forward declaration of operator==.
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+class hashtable;
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
+                const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2);
+
+// Hashtables handle allocators a bit differently than other containers
+//  do.  If we're using standard-conforming allocators, then a hashtable
+//  unconditionally has a member variable to hold its allocator, even if
+//  it so happens that all instances of the allocator type are identical.
+// This is because, for hashtables, this extra storage is negligible.
+//  Additionally, a base class wouldn't serve any other purposes; it
+//  wouldn't, for example, simplify the exception-handling code.
+
+template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
+          class _EqualKey, class _Alloc>
+class hashtable
+{
+public:
+  typedef _Key key_type;
+  typedef _Val value_type;
+  typedef _HashFcn hasher;
+  typedef _EqualKey key_equal;
+
+  typedef size_t size_type;
+  typedef ptrdiff_t difference_type;
+  typedef value_type* pointer;
+  typedef const value_type* const_pointer;
+  typedef value_type& reference;
+  typedef const value_type& const_reference;
+
+  hasher hash_funct() const { return _M_hash; }
+  key_equal key_eq() const { return _M_equals; }
+
+private:
+  typedef _Hashtable_node<_Val> _Node;
+
+public:
+  typedef typename _Alloc::template rebind<_Val>::other allocator_type;
+  allocator_type get_allocator() const { return _M_node_allocator; }
+private:
+  typedef
+    typename _Alloc::template rebind<_Node>::other _M_node_allocator_type;
+  typedef
+    typename _Alloc::template rebind<_Node*>::other _M_node_ptr_allocator_type;
+  typedef std::vector<_Node*, _M_node_ptr_allocator_type> _M_buckets_type;
+
+private:
+  _M_node_allocator_type _M_node_allocator;
+  hasher _M_hash;
+  key_equal _M_equals;
+  _ExtractKey _M_get_key;
+  _M_buckets_type _M_buckets;
+  size_type _M_num_elements;
+
+  _Node* _M_get_node() { return _M_node_allocator.allocate(1); }
+  void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); }
+
+public:
+  typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey,
+                              _Alloc>
+    iterator;
+  typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
+                                    _EqualKey, _Alloc>
+    const_iterator;
+
+  friend struct _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey,
+                                    _EqualKey, _Alloc>;
+  friend struct _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
+                                          _EqualKey, _Alloc>;
+
+public:
+  hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql,
+            const _ExtractKey& __ext,
+            const allocator_type& __a = allocator_type())
+    : _M_node_allocator(__a)
+    , _M_hash(__hf)
+    , _M_equals(__eql)
+    , _M_get_key(__ext)
+    , _M_buckets(__a)
+    , _M_num_elements(0)
+  {
+    _M_initialize_buckets(__n);
+  }
+
+  hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql,
+            const allocator_type& __a = allocator_type())
+    : _M_node_allocator(__a)
+    , _M_hash(__hf)
+    , _M_equals(__eql)
+    , _M_get_key(_ExtractKey())
+    , _M_buckets(__a)
+    , _M_num_elements(0)
+  {
+    _M_initialize_buckets(__n);
+  }
+
+  hashtable(const hashtable& __ht)
+    : _M_node_allocator(__ht.get_allocator())
+    , _M_hash(__ht._M_hash)
+    , _M_equals(__ht._M_equals)
+    , _M_get_key(__ht._M_get_key)
+    , _M_buckets(__ht.get_allocator())
+    , _M_num_elements(0)
+  {
+    _M_copy_from(__ht);
+  }
+
+  hashtable& operator=(const hashtable& __ht)
+  {
+    if (&__ht != this) {
+      clear();
+      _M_hash = __ht._M_hash;
+      _M_equals = __ht._M_equals;
+      _M_get_key = __ht._M_get_key;
+      _M_copy_from(__ht);
+    }
+    return *this;
+  }
+
+  ~hashtable() { clear(); }
+
+  size_type size() const { return _M_num_elements; }
+  size_type max_size() const { return size_type(-1); }
+  bool empty() const { return size() == 0; }
+
+  void swap(hashtable& __ht)
+  {
+    std::swap(_M_hash, __ht._M_hash);
+    std::swap(_M_equals, __ht._M_equals);
+    std::swap(_M_get_key, __ht._M_get_key);
+    _M_buckets.swap(__ht._M_buckets);
+    std::swap(_M_num_elements, __ht._M_num_elements);
+  }
+
+  iterator begin()
+  {
+    for (size_type __n = 0; __n < _M_buckets.size(); ++__n)
+      if (_M_buckets[__n])
+        return iterator(_M_buckets[__n], this);
+    return end();
+  }
+
+  iterator end() { return iterator(0, this); }
+
+  const_iterator begin() const
+  {
+    for (size_type __n = 0; __n < _M_buckets.size(); ++__n)
+      if (_M_buckets[__n])
+        return const_iterator(_M_buckets[__n], this);
+    return end();
+  }
+
+  const_iterator end() const { return const_iterator(0, this); }
+
+  friend bool operator==<>(const hashtable&, const hashtable&);
+
+public:
+  size_type bucket_count() const { return _M_buckets.size(); }
+
+  size_type max_bucket_count() const
+  {
+    return get_stl_prime_list()[(int)_stl_num_primes - 1];
+  }
+
+  size_type elems_in_bucket(size_type __bucket) const
+  {
+    size_type __result = 0;
+    for (_Node* __cur = _M_buckets[__bucket]; __cur; __cur = __cur->_M_next)
+      __result += 1;
+    return __result;
+  }
+
+  std::pair<iterator, bool> insert_unique(const value_type& __obj)
+  {
+    resize(_M_num_elements + 1);
+    return insert_unique_noresize(__obj);
+  }
+
+  iterator insert_equal(const value_type& __obj)
+  {
+    resize(_M_num_elements + 1);
+    return insert_equal_noresize(__obj);
+  }
+
+  std::pair<iterator, bool> insert_unique_noresize(const value_type& __obj);
+  iterator insert_equal_noresize(const value_type& __obj);
+
+  template <class _InputIterator>
+  void insert_unique(_InputIterator __f, _InputIterator __l)
+  {
+    insert_unique(
+      __f, __l,
+      typename std::iterator_traits<_InputIterator>::iterator_category());
+  }
+
+  template <class _InputIterator>
+  void insert_equal(_InputIterator __f, _InputIterator __l)
+  {
+    insert_equal(
+      __f, __l,
+      typename std::iterator_traits<_InputIterator>::iterator_category());
+  }
+
+  template <class _InputIterator>
+  void insert_unique(_InputIterator __f, _InputIterator __l,
+                     std::input_iterator_tag)
+  {
+    for (; __f != __l; ++__f)
+      insert_unique(*__f);
+  }
+
+  template <class _InputIterator>
+  void insert_equal(_InputIterator __f, _InputIterator __l,
+                    std::input_iterator_tag)
+  {
+    for (; __f != __l; ++__f)
+      insert_equal(*__f);
+  }
+
+  template <class _ForwardIterator>
+  void insert_unique(_ForwardIterator __f, _ForwardIterator __l,
+                     std::forward_iterator_tag)
+  {
+    size_type __n = 0;
+    std::distance(__f, __l, __n);
+    resize(_M_num_elements + __n);
+    for (; __n > 0; --__n, ++__f)
+      insert_unique_noresize(*__f);
+  }
+
+  template <class _ForwardIterator>
+  void insert_equal(_ForwardIterator __f, _ForwardIterator __l,
+                    std::forward_iterator_tag)
+  {
+    size_type __n = 0;
+    std::distance(__f, __l, __n);
+    resize(_M_num_elements + __n);
+    for (; __n > 0; --__n, ++__f)
+      insert_equal_noresize(*__f);
+  }
+
+  reference find_or_insert(const value_type& __obj);
+
+  iterator find(const key_type& __key)
+  {
+    size_type __n = _M_bkt_num_key(__key);
+    _Node* __first;
+    for (__first = _M_buckets[__n];
+         __first && !_M_equals(_M_get_key(__first->_M_val), __key);
+         __first = __first->_M_next) {
+    }
+    return iterator(__first, this);
+  }
+
+  const_iterator find(const key_type& __key) const
+  {
+    size_type __n = _M_bkt_num_key(__key);
+    const _Node* __first;
+    for (__first = _M_buckets[__n];
+         __first && !_M_equals(_M_get_key(__first->_M_val), __key);
+         __first = __first->_M_next) {
+    }
+    return const_iterator(__first, this);
+  }
+
+  size_type count(const key_type& __key) const
+  {
+    const size_type __n = _M_bkt_num_key(__key);
+    size_type __result = 0;
+
+    for (const _Node* __cur = _M_buckets[__n]; __cur; __cur = __cur->_M_next)
+      if (_M_equals(_M_get_key(__cur->_M_val), __key))
+        ++__result;
+    return __result;
+  }
+
+  std::pair<iterator, iterator> equal_range(const key_type& __key);
+
+  std::pair<const_iterator, const_iterator> equal_range(
+    const key_type& __key) const;
+
+  size_type erase(const key_type& __key);
+  void erase(const iterator& __it);
+  void erase(iterator __first, iterator __last);
+
+  void erase(const const_iterator& __it);
+  void erase(const_iterator __first, const_iterator __last);
+
+  void resize(size_type __num_elements_hint);
+  void clear();
+
+private:
+  size_type _M_next_size(size_type __n) const { return _stl_next_prime(__n); }
+
+  void _M_initialize_buckets(size_type __n)
+  {
+    const size_type __n_buckets = _M_next_size(__n);
+    _M_buckets.reserve(__n_buckets);
+    _M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*)0);
+    _M_num_elements = 0;
+  }
+
+  size_type _M_bkt_num_key(const key_type& __key) const
+  {
+    return _M_bkt_num_key(__key, _M_buckets.size());
+  }
+
+  size_type _M_bkt_num(const value_type& __obj) const
+  {
+    return _M_bkt_num_key(_M_get_key(__obj));
+  }
+
+  size_type _M_bkt_num_key(const key_type& __key, size_t __n) const
+  {
+    return _M_hash(__key) % __n;
+  }
+
+  size_type _M_bkt_num(const value_type& __obj, size_t __n) const
+  {
+    return _M_bkt_num_key(_M_get_key(__obj), __n);
+  }
+
+  void construct(_Val* p, const _Val& v) { new (p) _Val(v); }
+  void destroy(_Val* p)
+  {
+    (void)p;
+    p->~_Val();
+  }
+
+  _Node* _M_new_node(const value_type& __obj)
+  {
+    _Node* __n = _M_get_node();
+    __n->_M_next = 0;
+    try {
+      construct(&__n->_M_val, __obj);
+      return __n;
+    } catch (...) {
+      _M_put_node(__n);
+      throw;
+    }
+  }
+
+  void _M_delete_node(_Node* __n)
+  {
+    destroy(&__n->_M_val);
+    _M_put_node(__n);
+  }
+
+  void _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last);
+  void _M_erase_bucket(const size_type __n, _Node* __last);
+
+  void _M_copy_from(const hashtable& __ht);
+};
+
+template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
+          class _All>
+_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>&
+  _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++()
+{
+  const _Node* __old = _M_cur;
+  _M_cur = _M_cur->_M_next;
+  if (!_M_cur) {
+    size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
+    while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
+      _M_cur = _M_ht->_M_buckets[__bucket];
+  }
+  return *this;
+}
+
+template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
+          class _All>
+inline _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>
+  _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int)
+{
+  iterator __tmp = *this;
+  ++*this;
+  return __tmp;
+}
+
+template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
+          class _All>
+_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>&
+  _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++()
+{
+  const _Node* __old = _M_cur;
+  _M_cur = _M_cur->_M_next;
+  if (!_M_cur) {
+    size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
+    while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
+      _M_cur = _M_ht->_M_buckets[__bucket];
+  }
+  return *this;
+}
+
+template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
+          class _All>
+inline _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>
+  _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int)
+{
+  const_iterator __tmp = *this;
+  ++*this;
+  return __tmp;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
+                const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2)
+{
+  typedef typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_Node _Node;
+  if (__ht1._M_buckets.size() != __ht2._M_buckets.size())
+    return false;
+  for (int __n = 0; __n < __ht1._M_buckets.size(); ++__n) {
+    _Node* __cur1 = __ht1._M_buckets[__n];
+    _Node* __cur2 = __ht2._M_buckets[__n];
+    for (; __cur1 && __cur2 && __cur1->_M_val == __cur2->_M_val;
+         __cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next) {
+    }
+    if (__cur1 || __cur2)
+      return false;
+  }
+  return true;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+inline bool operator!=(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
+                       const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2)
+{
+  return !(__ht1 == __ht2);
+}
+
+template <class _Val, class _Key, class _HF, class _Extract, class _EqKey,
+          class _All>
+inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1,
+                 hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2)
+{
+  __ht1.swap(__ht2);
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator, bool>
+hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_unique_noresize(
+  const value_type& __obj)
+{
+  const size_type __n = _M_bkt_num(__obj);
+  _Node* __first = _M_buckets[__n];
+
+  for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
+    if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
+      return std::pair<iterator, bool>(iterator(__cur, this), false);
+
+  _Node* __tmp = _M_new_node(__obj);
+  __tmp->_M_next = __first;
+  _M_buckets[__n] = __tmp;
+  ++_M_num_elements;
+  return std::pair<iterator, bool>(iterator(__tmp, this), true);
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator
+hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_equal_noresize(
+  const value_type& __obj)
+{
+  const size_type __n = _M_bkt_num(__obj);
+  _Node* __first = _M_buckets[__n];
+
+  for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
+    if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) {
+      _Node* __tmp = _M_new_node(__obj);
+      __tmp->_M_next = __cur->_M_next;
+      __cur->_M_next = __tmp;
+      ++_M_num_elements;
+      return iterator(__tmp, this);
+    }
+
+  _Node* __tmp = _M_new_node(__obj);
+  __tmp->_M_next = __first;
+  _M_buckets[__n] = __tmp;
+  ++_M_num_elements;
+  return iterator(__tmp, this);
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::reference hashtable<
+  _Val, _Key, _HF, _Ex, _Eq, _All>::find_or_insert(const value_type& __obj)
+{
+  resize(_M_num_elements + 1);
+
+  size_type __n = _M_bkt_num(__obj);
+  _Node* __first = _M_buckets[__n];
+
+  for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
+    if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
+      return __cur->_M_val;
+
+  _Node* __tmp = _M_new_node(__obj);
+  __tmp->_M_next = __first;
+  _M_buckets[__n] = __tmp;
+  ++_M_num_elements;
+  return __tmp->_M_val;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator,
+          typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator>
+hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range(const key_type& __key)
+{
+  typedef std::pair<iterator, iterator> _Pii;
+  const size_type __n = _M_bkt_num_key(__key);
+
+  for (_Node* __first = _M_buckets[__n]; __first; __first = __first->_M_next)
+    if (_M_equals(_M_get_key(__first->_M_val), __key)) {
+      for (_Node* __cur = __first->_M_next; __cur; __cur = __cur->_M_next)
+        if (!_M_equals(_M_get_key(__cur->_M_val), __key))
+          return _Pii(iterator(__first, this), iterator(__cur, this));
+      for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
+        if (_M_buckets[__m])
+          return _Pii(iterator(__first, this),
+                      iterator(_M_buckets[__m], this));
+      return _Pii(iterator(__first, this), end());
+    }
+  return _Pii(end(), end());
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator,
+          typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator>
+hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range(
+  const key_type& __key) const
+{
+  typedef std::pair<const_iterator, const_iterator> _Pii;
+  const size_type __n = _M_bkt_num_key(__key);
+
+  for (const _Node* __first = _M_buckets[__n]; __first;
+       __first = __first->_M_next) {
+    if (_M_equals(_M_get_key(__first->_M_val), __key)) {
+      for (const _Node* __cur = __first->_M_next; __cur;
+           __cur = __cur->_M_next)
+        if (!_M_equals(_M_get_key(__cur->_M_val), __key))
+          return _Pii(const_iterator(__first, this),
+                      const_iterator(__cur, this));
+      for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
+        if (_M_buckets[__m])
+          return _Pii(const_iterator(__first, this),
+                      const_iterator(_M_buckets[__m], this));
+      return _Pii(const_iterator(__first, this), end());
+    }
+  }
+  return _Pii(end(), end());
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::size_type
+hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const key_type& __key)
+{
+  const size_type __n = _M_bkt_num_key(__key);
+  _Node* __first = _M_buckets[__n];
+  size_type __erased = 0;
+
+  if (__first) {
+    _Node* __cur = __first;
+    _Node* __next = __cur->_M_next;
+    while (__next) {
+      if (_M_equals(_M_get_key(__next->_M_val), __key)) {
+        __cur->_M_next = __next->_M_next;
+        _M_delete_node(__next);
+        __next = __cur->_M_next;
+        ++__erased;
+        --_M_num_elements;
+      } else {
+        __cur = __next;
+        __next = __cur->_M_next;
+      }
+    }
+    if (_M_equals(_M_get_key(__first->_M_val), __key)) {
+      _M_buckets[__n] = __first->_M_next;
+      _M_delete_node(__first);
+      ++__erased;
+      --_M_num_elements;
+    }
+  }
+  return __erased;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const iterator& __it)
+{
+  _Node* __p = __it._M_cur;
+  if (__p) {
+    const size_type __n = _M_bkt_num(__p->_M_val);
+    _Node* __cur = _M_buckets[__n];
+
+    if (__cur == __p) {
+      _M_buckets[__n] = __cur->_M_next;
+      _M_delete_node(__cur);
+      --_M_num_elements;
+    } else {
+      _Node* __next = __cur->_M_next;
+      while (__next) {
+        if (__next == __p) {
+          __cur->_M_next = __next->_M_next;
+          _M_delete_node(__next);
+          --_M_num_elements;
+          break;
+        } else {
+          __cur = __next;
+          __next = __cur->_M_next;
+        }
+      }
+    }
+  }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(iterator __first,
+                                                       iterator __last)
+{
+  size_type __f_bucket =
+    __first._M_cur ? _M_bkt_num(__first._M_cur->_M_val) : _M_buckets.size();
+  size_type __l_bucket =
+    __last._M_cur ? _M_bkt_num(__last._M_cur->_M_val) : _M_buckets.size();
+
+  if (__first._M_cur == __last._M_cur)
+    return;
+  else if (__f_bucket == __l_bucket)
+    _M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur);
+  else {
+    _M_erase_bucket(__f_bucket, __first._M_cur, 0);
+    for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n)
+      _M_erase_bucket(__n, 0);
+    if (__l_bucket != _M_buckets.size())
+      _M_erase_bucket(__l_bucket, __last._M_cur);
+  }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(
+  const_iterator __first, const_iterator __last)
+{
+  erase(iterator(const_cast<_Node*>(__first._M_cur),
+                 const_cast<hashtable*>(__first._M_ht)),
+        iterator(const_cast<_Node*>(__last._M_cur),
+                 const_cast<hashtable*>(__last._M_ht)));
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(
+  const const_iterator& __it)
+{
+  erase(iterator(const_cast<_Node*>(__it._M_cur),
+                 const_cast<hashtable*>(__it._M_ht)));
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::resize(
+  size_type __num_elements_hint)
+{
+  const size_type __old_n = _M_buckets.size();
+  if (__num_elements_hint > __old_n) {
+    const size_type __n = _M_next_size(__num_elements_hint);
+    if (__n > __old_n) {
+      _M_buckets_type __tmp(__n, (_Node*)(0), _M_buckets.get_allocator());
+      try {
+        for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) {
+          _Node* __first = _M_buckets[__bucket];
+          while (__first) {
+            size_type __new_bucket = _M_bkt_num(__first->_M_val, __n);
+            _M_buckets[__bucket] = __first->_M_next;
+            __first->_M_next = __tmp[__new_bucket];
+            __tmp[__new_bucket] = __first;
+            __first = _M_buckets[__bucket];
+          }
+        }
+        _M_buckets.swap(__tmp);
+      } catch (...) {
+        for (size_type __bucket = 0; __bucket < __tmp.size(); ++__bucket) {
+          while (__tmp[__bucket]) {
+            _Node* __next = __tmp[__bucket]->_M_next;
+            _M_delete_node(__tmp[__bucket]);
+            __tmp[__bucket] = __next;
+          }
+        }
+        throw;
+      }
+    }
+  }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket(
+  const size_type __n, _Node* __first, _Node* __last)
+{
+  _Node* __cur = _M_buckets[__n];
+  if (__cur == __first)
+    _M_erase_bucket(__n, __last);
+  else {
+    _Node* __next;
+    for (__next = __cur->_M_next; __next != __first;
+         __cur = __next, __next = __cur->_M_next)
+      ;
+    while (__next != __last) {
+      __cur->_M_next = __next->_M_next;
+      _M_delete_node(__next);
+      __next = __cur->_M_next;
+      --_M_num_elements;
+    }
+  }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket(
+  const size_type __n, _Node* __last)
+{
+  _Node* __cur = _M_buckets[__n];
+  while (__cur != __last) {
+    _Node* __next = __cur->_M_next;
+    _M_delete_node(__cur);
+    __cur = __next;
+    _M_buckets[__n] = __cur;
+    --_M_num_elements;
+  }
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::clear()
+{
+  for (size_type __i = 0; __i < _M_buckets.size(); ++__i) {
+    _Node* __cur = _M_buckets[__i];
+    while (__cur != 0) {
+      _Node* __next = __cur->_M_next;
+      _M_delete_node(__cur);
+      __cur = __next;
+    }
+    _M_buckets[__i] = 0;
+  }
+  _M_num_elements = 0;
+}
+
+template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
+void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_copy_from(
+  const hashtable& __ht)
+{
+  _M_buckets.clear();
+  _M_buckets.reserve(__ht._M_buckets.size());
+  _M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*)0);
+  try {
+    for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) {
+      const _Node* __cur = __ht._M_buckets[__i];
+      if (__cur) {
+        _Node* __copy = _M_new_node(__cur->_M_val);
+        _M_buckets[__i] = __copy;
+
+        for (_Node *__next = __cur->_M_next; __next;
+             __cur = __next, __next = __cur->_M_next) {
+          __copy->_M_next = _M_new_node(__next->_M_val);
+          __copy = __copy->_M_next;
+        }
+      }
+    }
+    _M_num_elements = __ht._M_num_elements;
+  } catch (...) {
+    clear();
+    throw;
+  }
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+// Undo warning suppression.
+#if defined(__clang__) && defined(__has_warning)
+#if __has_warning("-Wdeprecated")
+#pragma clang diagnostic pop
+#endif
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/kwsysHeaderDump.pl b/thirdparty/KWSys/adios2sys/kwsysHeaderDump.pl
new file mode 100755
index 0000000000000000000000000000000000000000..e3391e762322bbf1d55d4c23d5e44d5d624ad72e
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/kwsysHeaderDump.pl
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
+
+if ( $#ARGV+1 < 2 )
+{
+    print "Usage: ./kwsysHeaderDump.pl <name> <header>\n";
+    exit(1);
+}
+
+$name = $ARGV[0];
+$max = 0;
+open(INFILE, $ARGV[1]);
+while (chomp ($line = <INFILE>))
+{
+    if (($line !~ /^\#/) &&
+        ($line =~ s/.*kwsys${name}_([A-Za-z0-9_]*).*/\1/) &&
+        ($i{$line}++ < 1))
+    {
+        push(@lines, "$line");
+        if (length($line) > $max)
+        {
+            $max = length($line);
+        }
+    }
+}
+close(INFILE);
+
+$width = $max + 13;
+print sprintf("#define %-${width}s kwsys_ns(${name})\n", "kwsys${name}");
+foreach $l (@lines)
+{
+    print sprintf("#define %-${width}s kwsys_ns(${name}_$l)\n",
+                  "kwsys${name}_$l");
+}
+print "\n";
+print sprintf("# undef kwsys${name}\n");
+foreach $l (@lines)
+{
+    print sprintf("# undef kwsys${name}_$l\n");
+}
diff --git a/thirdparty/KWSys/adios2sys/kwsysPlatformTests.cmake b/thirdparty/KWSys/adios2sys/kwsysPlatformTests.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..5386a49a33518e6a5d49673c0c28634edbe495b9
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/kwsysPlatformTests.cmake
@@ -0,0 +1,211 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
+
+SET(KWSYS_PLATFORM_TEST_FILE_C kwsysPlatformTestsC.c)
+SET(KWSYS_PLATFORM_TEST_FILE_CXX kwsysPlatformTestsCXX.cxx)
+
+MACRO(KWSYS_PLATFORM_TEST lang var description invert)
+  IF(NOT DEFINED ${var}_COMPILED)
+    MESSAGE(STATUS "${description}")
+    TRY_COMPILE(${var}_COMPILED
+      ${CMAKE_CURRENT_BINARY_DIR}
+      ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
+      COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS}
+      CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}"
+      OUTPUT_VARIABLE OUTPUT)
+    IF(${var}_COMPILED)
+      FILE(APPEND
+        ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "${description} compiled with the following output:\n${OUTPUT}\n\n")
+    ELSE()
+      FILE(APPEND
+        ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "${description} failed to compile with the following output:\n${OUTPUT}\n\n")
+    ENDIF()
+    IF(${invert} MATCHES INVERT)
+      IF(${var}_COMPILED)
+        MESSAGE(STATUS "${description} - no")
+      ELSE()
+        MESSAGE(STATUS "${description} - yes")
+      ENDIF()
+    ELSE()
+      IF(${var}_COMPILED)
+        MESSAGE(STATUS "${description} - yes")
+      ELSE()
+        MESSAGE(STATUS "${description} - no")
+      ENDIF()
+    ENDIF()
+  ENDIF()
+  IF(${invert} MATCHES INVERT)
+    IF(${var}_COMPILED)
+      SET(${var} 0)
+    ELSE()
+      SET(${var} 1)
+    ENDIF()
+  ELSE()
+    IF(${var}_COMPILED)
+      SET(${var} 1)
+    ELSE()
+      SET(${var} 0)
+    ENDIF()
+  ENDIF()
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_TEST_RUN lang var description invert)
+  IF(NOT DEFINED ${var})
+    MESSAGE(STATUS "${description}")
+    TRY_RUN(${var} ${var}_COMPILED
+      ${CMAKE_CURRENT_BINARY_DIR}
+      ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
+      COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS}
+      OUTPUT_VARIABLE OUTPUT)
+
+    # Note that ${var} will be a 0 return value on success.
+    IF(${var}_COMPILED)
+      IF(${var})
+        FILE(APPEND
+          ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+          "${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n")
+      ELSE()
+        FILE(APPEND
+          ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+          "${description} compiled and ran with the following output:\n${OUTPUT}\n\n")
+      ENDIF()
+    ELSE()
+      FILE(APPEND
+        ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "${description} failed to compile with the following output:\n${OUTPUT}\n\n")
+      SET(${var} -1 CACHE INTERNAL "${description} failed to compile.")
+    ENDIF()
+
+    IF(${invert} MATCHES INVERT)
+      IF(${var}_COMPILED)
+        IF(${var})
+          MESSAGE(STATUS "${description} - yes")
+        ELSE()
+          MESSAGE(STATUS "${description} - no")
+        ENDIF()
+      ELSE()
+        MESSAGE(STATUS "${description} - failed to compile")
+      ENDIF()
+    ELSE()
+      IF(${var}_COMPILED)
+        IF(${var})
+          MESSAGE(STATUS "${description} - no")
+        ELSE()
+          MESSAGE(STATUS "${description} - yes")
+        ENDIF()
+      ELSE()
+        MESSAGE(STATUS "${description} - failed to compile")
+      ENDIF()
+    ENDIF()
+  ENDIF()
+
+  IF(${invert} MATCHES INVERT)
+    IF(${var}_COMPILED)
+      IF(${var})
+        SET(${var} 1)
+      ELSE()
+        SET(${var} 0)
+      ENDIF()
+    ELSE()
+      SET(${var} 1)
+    ENDIF()
+  ELSE()
+    IF(${var}_COMPILED)
+      IF(${var})
+        SET(${var} 0)
+      ELSE()
+        SET(${var} 1)
+      ENDIF()
+    ELSE()
+      SET(${var} 0)
+    ENDIF()
+  ENDIF()
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_C_TEST var description invert)
+  SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES})
+  SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS})
+  KWSYS_PLATFORM_TEST(C "${var}" "${description}" "${invert}")
+  SET(KWSYS_PLATFORM_TEST_DEFINES)
+  SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_C_TEST_RUN var description invert)
+  SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES})
+  SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS})
+  KWSYS_PLATFORM_TEST_RUN(C "${var}" "${description}" "${invert}")
+  SET(KWSYS_PLATFORM_TEST_DEFINES)
+  SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_CXX_TEST var description invert)
+  SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES})
+  SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS})
+  SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES})
+  KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}")
+  SET(KWSYS_PLATFORM_TEST_DEFINES)
+  SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
+  SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES)
+ENDMACRO()
+
+MACRO(KWSYS_PLATFORM_CXX_TEST_RUN var description invert)
+  SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES})
+  SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS})
+  KWSYS_PLATFORM_TEST_RUN(CXX "${var}" "${description}" "${invert}")
+  SET(KWSYS_PLATFORM_TEST_DEFINES)
+  SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
+ENDMACRO()
+
+#-----------------------------------------------------------------------------
+# KWSYS_PLATFORM_INFO_TEST(lang var description)
+#
+# Compile test named by ${var} and store INFO strings extracted from binary.
+MACRO(KWSYS_PLATFORM_INFO_TEST lang var description)
+  # We can implement this macro on CMake 2.6 and above.
+  IF("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6)
+    SET(${var} "")
+  ELSE()
+    # Choose a location for the result binary.
+    SET(KWSYS_PLATFORM_INFO_FILE
+      ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${var}.bin)
+
+    # Compile the test binary.
+    IF(NOT EXISTS ${KWSYS_PLATFORM_INFO_FILE})
+      MESSAGE(STATUS "${description}")
+      TRY_COMPILE(${var}_COMPILED
+        ${CMAKE_CURRENT_BINARY_DIR}
+        ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
+        COMPILE_DEFINITIONS -DTEST_${var}
+          ${KWSYS_PLATFORM_${lang}_TEST_DEFINES}
+          ${KWSYS_PLATFORM_${lang}_TEST_EXTRA_FLAGS}
+        OUTPUT_VARIABLE OUTPUT
+        COPY_FILE ${KWSYS_PLATFORM_INFO_FILE}
+        )
+      IF(${var}_COMPILED)
+        FILE(APPEND
+          ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+          "${description} compiled with the following output:\n${OUTPUT}\n\n")
+      ELSE()
+        FILE(APPEND
+          ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+          "${description} failed to compile with the following output:\n${OUTPUT}\n\n")
+      ENDIF()
+      IF(${var}_COMPILED)
+        MESSAGE(STATUS "${description} - compiled")
+      ELSE()
+        MESSAGE(STATUS "${description} - failed")
+      ENDIF()
+    ENDIF()
+
+    # Parse info strings out of the compiled binary.
+    IF(${var}_COMPILED)
+      FILE(STRINGS ${KWSYS_PLATFORM_INFO_FILE} ${var} REGEX "INFO:[A-Za-z0-9]+\\[[^]]*\\]")
+    ELSE()
+      SET(${var} "")
+    ENDIF()
+
+    SET(KWSYS_PLATFORM_INFO_FILE)
+  ENDIF()
+ENDMACRO()
diff --git a/thirdparty/KWSys/adios2sys/kwsysPlatformTestsC.c b/thirdparty/KWSys/adios2sys/kwsysPlatformTestsC.c
new file mode 100644
index 0000000000000000000000000000000000000000..d12fac0b6653aa8da1a7bebc8b08fbee040e1e33
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/kwsysPlatformTestsC.c
@@ -0,0 +1,96 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+/*
+  Macros to define main() in a cross-platform way.
+
+  Usage:
+
+    int KWSYS_PLATFORM_TEST_C_MAIN()
+    {
+      return 0;
+    }
+
+    int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv)
+    {
+      (void)argc; (void)argv;
+      return 0;
+    }
+*/
+#if defined(__CLASSIC_C__)
+#define KWSYS_PLATFORM_TEST_C_MAIN() main()
+#define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv)                           \
+  main(argc, argv) int argc;                                                  \
+  char* argv[];
+#else
+#define KWSYS_PLATFORM_TEST_C_MAIN() main(void)
+#define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv)                           \
+  main(int argc, char* argv[])
+#endif
+
+/*--------------------------------------------------------------------------*/
+#ifdef TEST_KWSYS_C_HAS_PTRDIFF_T
+#include <stddef.h>
+int f(ptrdiff_t n)
+{
+  return n > 0;
+}
+int KWSYS_PLATFORM_TEST_C_MAIN()
+{
+  char* p = 0;
+  ptrdiff_t d = p - p;
+  (void)d;
+  return f(p - p);
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+#ifdef TEST_KWSYS_C_HAS_SSIZE_T
+#include <unistd.h>
+int f(ssize_t n)
+{
+  return (int)n;
+}
+int KWSYS_PLATFORM_TEST_C_MAIN()
+{
+  ssize_t n = 0;
+  return f(n);
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+#ifdef TEST_KWSYS_C_TYPE_MACROS
+char* info_macros =
+#if defined(__SIZEOF_SHORT__)
+  "INFO:macro[__SIZEOF_SHORT__]\n"
+#endif
+#if defined(__SIZEOF_INT__)
+  "INFO:macro[__SIZEOF_INT__]\n"
+#endif
+#if defined(__SIZEOF_LONG__)
+  "INFO:macro[__SIZEOF_LONG__]\n"
+#endif
+#if defined(__SIZEOF_LONG_LONG__)
+  "INFO:macro[__SIZEOF_LONG_LONG__]\n"
+#endif
+#if defined(__SHORT_MAX__)
+  "INFO:macro[__SHORT_MAX__]\n"
+#endif
+#if defined(__INT_MAX__)
+  "INFO:macro[__INT_MAX__]\n"
+#endif
+#if defined(__LONG_MAX__)
+  "INFO:macro[__LONG_MAX__]\n"
+#endif
+#if defined(__LONG_LONG_MAX__)
+  "INFO:macro[__LONG_LONG_MAX__]\n"
+#endif
+  "";
+
+int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv)
+{
+  int require = 0;
+  require += info_macros[argc];
+  (void)argv;
+  return require;
+}
+#endif
diff --git a/thirdparty/KWSys/adios2sys/kwsysPlatformTestsCXX.cxx b/thirdparty/KWSys/adios2sys/kwsysPlatformTestsCXX.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..01c69514c0cc2f255d1bcadf4c5066880d9eed95
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/kwsysPlatformTestsCXX.cxx
@@ -0,0 +1,371 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifdef TEST_KWSYS_CXX_HAS_CSTDIO
+#include <cstdio>
+int main()
+{
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_LONG_LONG
+long long f(long long n)
+{
+  return n;
+}
+int main()
+{
+  long long n = 0;
+  return static_cast<int>(f(n));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS___INT64
+__int64 f(__int64 n)
+{
+  return n;
+}
+int main()
+{
+  __int64 n = 0;
+  return static_cast<int>(f(n));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIM
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+int main()
+{
+  struct stat stat1;
+  (void)stat1.st_mtim.tv_sec;
+  (void)stat1.st_mtim.tv_nsec;
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+int main()
+{
+  struct stat stat1;
+  (void)stat1.st_mtimespec.tv_sec;
+  (void)stat1.st_mtimespec.tv_nsec;
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_SAME_LONG_AND___INT64
+void function(long**)
+{
+}
+int main()
+{
+  __int64** p = 0;
+  function(p);
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_SAME_LONG_LONG_AND___INT64
+void function(long long**)
+{
+}
+int main()
+{
+  __int64** p = 0;
+  function(p);
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+#include <iostream>
+int test_istream(std::istream& is, long long& x)
+{
+  return (is >> x) ? 1 : 0;
+}
+int main()
+{
+  long long x = 0;
+  return test_istream(std::cin, x);
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+#include <iostream>
+int test_ostream(std::ostream& os, long long x)
+{
+  return (os << x) ? 1 : 0;
+}
+int main()
+{
+  long long x = 0;
+  return test_ostream(std::cout, x);
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_ISTREAM___INT64
+#include <iostream>
+int test_istream(std::istream& is, __int64& x)
+{
+  return (is >> x) ? 1 : 0;
+}
+int main()
+{
+  __int64 x = 0;
+  return test_istream(std::cin, x);
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_OSTREAM___INT64
+#include <iostream>
+int test_ostream(std::ostream& os, __int64 x)
+{
+  return (os << x) ? 1 : 0;
+}
+int main()
+{
+  __int64 x = 0;
+  return test_ostream(std::cout, x);
+}
+#endif
+
+#ifdef TEST_KWSYS_LFS_WORKS
+/* Return 0 when LFS is available and 1 otherwise.  */
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#define _LARGE_FILES
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+
+#include <assert.h>
+#include <sys/stat.h>
+#if KWSYS_CXX_HAS_CSTDIO
+#include <cstdio>
+#endif
+#include <stdio.h>
+
+int main(int, char** argv)
+{
+/* check that off_t can hold 2^63 - 1 and perform basic operations... */
+#define OFF_T_64 (((off_t)1 << 62) - 1 + ((off_t)1 << 62))
+  if (OFF_T_64 % 2147483647 != 1)
+    return 1;
+
+  // stat breaks on SCO OpenServer
+  struct stat buf;
+  stat(argv[0], &buf);
+  if (!S_ISREG(buf.st_mode))
+    return 2;
+
+  FILE* file = fopen(argv[0], "r");
+  off_t offset = ftello(file);
+  fseek(file, offset, SEEK_CUR);
+  fclose(file);
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_SETENV
+#include <stdlib.h>
+int main()
+{
+  return setenv("A", "B", 1);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_UNSETENV
+#include <stdlib.h>
+int main()
+{
+  unsetenv("A");
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
+#include <stdlib.h>
+int main()
+{
+  char* e = environ[0];
+  return e ? 0 : 1;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_GETLOADAVG
+// Match feature definitions from SystemInformation.cxx
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#include <stdlib.h>
+int main()
+{
+  double loadavg[3] = { 0.0, 0.0, 0.0 };
+  return getloadavg(loadavg, 3);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64
+#if defined(KWSYS_HAS_LFS)
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#define _LARGE_FILES
+#define _FILE_OFFSET_BITS 64
+#endif
+#include <sys/resource.h>
+int main()
+{
+  struct rlimit64 rlim;
+  return getrlimit64(0, &rlim);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_ATOLL
+#include <stdlib.h>
+int main()
+{
+  const char* str = "1024";
+  return static_cast<int>(atoll(str));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_ATOL
+#include <stdlib.h>
+int main()
+{
+  const char* str = "1024";
+  return static_cast<int>(atol(str));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS__ATOI64
+#include <stdlib.h>
+int main()
+{
+  const char* str = "1024";
+  return static_cast<int>(_atoi64(str));
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_UTIMES
+#include <sys/time.h>
+int main()
+{
+  struct timeval* current_time = 0;
+  return utimes("/example", current_time);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_UTIMENSAT
+#include <fcntl.h>
+#include <sys/stat.h>
+int main()
+{
+  struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, UTIME_NOW } };
+  return utimensat(AT_FDCWD, "/example", times, AT_SYMLINK_NOFOLLOW);
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_BACKTRACE
+#if defined(__PATHSCALE__) || defined(__PATHCC__) ||                          \
+  (defined(__LSB_VERSION__) && (__LSB_VERSION__ < 41))
+backtrace doesnt work with this compiler or os
+#endif
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#include <execinfo.h>
+int main()
+{
+  void* stackSymbols[256];
+  backtrace(stackSymbols, 256);
+  backtrace_symbols(&stackSymbols[0], 1);
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_DLADDR
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#include <dlfcn.h>
+int main()
+{
+  Dl_info info;
+  int ierr = dladdr((void*)main, &info);
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_CXXABI
+#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5130 && __linux &&               \
+  __SUNPRO_CC_COMPAT == 'G'
+#include <iostream>
+#endif
+#include <cxxabi.h>
+int main()
+{
+  int status = 0;
+  size_t bufferLen = 512;
+  char buffer[512] = { '\0' };
+  const char* function = "_ZN5kwsys17SystemInformation15GetProgramStackEii";
+  char* demangledFunction =
+    abi::__cxa_demangle(function, buffer, &bufferLen, &status);
+  return status;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM
+int main()
+{
+  int a = 1;
+  __asm {
+    xor EBX, EBX;
+    mov a, EBX;
+  }
+
+  return a;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM_CPUID
+int main()
+{
+  int a = 0;
+  __asm {
+    xor EAX, EAX;
+    cpuid;
+    mov a, EAX;
+  }
+
+  return a;
+}
+#endif
+
+#ifdef TEST_KWSYS_STL_HAS_WSTRING
+#include <string>
+void f(std::wstring*)
+{
+}
+int main()
+{
+  return 0;
+}
+#endif
+
+#ifdef TEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H
+#include <ext/stdio_filebuf.h>
+int main()
+{
+  return 0;
+}
+#endif
diff --git a/thirdparty/KWSys/adios2sys/kwsysPrivate.h b/thirdparty/KWSys/adios2sys/kwsysPrivate.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce1b53ed857d374bfbe3e540fa2061d9651ec899
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/kwsysPrivate.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef KWSYS_NAMESPACE
+#error "Do not include kwsysPrivate.h outside of kwsys c and cxx files."
+#endif
+
+#ifndef _kwsysPrivate_h
+#define _kwsysPrivate_h
+
+/*
+  Define KWSYS_HEADER macro to help the c and cxx files include kwsys
+  headers from the configured namespace directory.  The macro can be
+  used like this:
+
+  #include KWSYS_HEADER(Directory.hxx)
+  #include KWSYS_HEADER(std/vector)
+*/
+/* clang-format off */
+#define KWSYS_HEADER(x) KWSYS_HEADER0(KWSYS_NAMESPACE/x)
+/* clang-format on */
+#define KWSYS_HEADER0(x) KWSYS_HEADER1(x)
+#define KWSYS_HEADER1(x) <x>
+
+/*
+  Define KWSYS_NAMESPACE_STRING to be a string constant containing the
+  name configured for this instance of the kwsys library.
+*/
+#define KWSYS_NAMESPACE_STRING KWSYS_NAMESPACE_STRING0(KWSYS_NAMESPACE)
+#define KWSYS_NAMESPACE_STRING0(x) KWSYS_NAMESPACE_STRING1(x)
+#define KWSYS_NAMESPACE_STRING1(x) #x
+
+#else
+#error "kwsysPrivate.h included multiple times."
+#endif
diff --git a/thirdparty/KWSys/adios2sys/testCommandLineArguments.cxx b/thirdparty/KWSys/adios2sys/testCommandLineArguments.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d2215d62f6428d9c8604fa9bd655bd15d1065e7c
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testCommandLineArguments.cxx
@@ -0,0 +1,208 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(CommandLineArguments.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "CommandLineArguments.hxx.in"
+#endif
+
+#include <iostream>
+#include <vector>
+
+#include <stddef.h> /* size_t */
+#include <string.h> /* strcmp */
+
+static void* random_ptr = reinterpret_cast<void*>(0x123);
+
+static int argument(const char* arg, const char* value, void* call_data)
+{
+  std::cout << "Got argument: \"" << arg << "\" value: \""
+            << (value ? value : "(null)") << "\"" << std::endl;
+  if (call_data != random_ptr) {
+    std::cerr << "Problem processing call_data" << std::endl;
+    return 0;
+  }
+  return 1;
+}
+
+static int unknown_argument(const char* argument, void* call_data)
+{
+  std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl;
+  if (call_data != random_ptr) {
+    std::cerr << "Problem processing call_data" << std::endl;
+    return 0;
+  }
+  return 1;
+}
+
+static bool CompareTwoItemsOnList(bool i1, bool i2)
+{
+  return i1 == i2;
+}
+static bool CompareTwoItemsOnList(int i1, int i2)
+{
+  return i1 == i2;
+}
+static bool CompareTwoItemsOnList(double i1, double i2)
+{
+  return i1 == i2;
+}
+static bool CompareTwoItemsOnList(const char* i1, const char* i2)
+{
+  return strcmp(i1, i2) == 0;
+}
+static bool CompareTwoItemsOnList(const std::string& i1, const std::string& i2)
+{
+  return i1 == i2;
+}
+
+int testCommandLineArguments(int argc, char* argv[])
+{
+  // Example run: ./testCommandLineArguments --some-int-variable 4
+  // --another-bool-variable --some-bool-variable=yes
+  // --some-stl-string-variable=foobar --set-bool-arg1 --set-bool-arg2
+  // --some-string-variable=hello
+
+  int res = 0;
+  kwsys::CommandLineArguments arg;
+  arg.Initialize(argc, argv);
+
+  // For error handling
+  arg.SetClientData(random_ptr);
+  arg.SetUnknownArgumentCallback(unknown_argument);
+
+  int some_int_variable = 10;
+  double some_double_variable = 10.10;
+  char* some_string_variable = 0;
+  std::string some_stl_string_variable = "";
+  bool some_bool_variable = false;
+  bool some_bool_variable1 = false;
+  bool bool_arg1 = false;
+  int bool_arg2 = 0;
+
+  std::vector<int> numbers_argument;
+  int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 };
+
+  std::vector<double> doubles_argument;
+  double valid_doubles[] = { 12.5, 1.31, 22 };
+
+  std::vector<bool> bools_argument;
+  bool valid_bools[] = { true, true, false };
+
+  std::vector<char*> strings_argument;
+  const char* valid_strings[] = { "andy", "bill", "brad", "ken" };
+
+  std::vector<std::string> stl_strings_argument;
+  std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" };
+
+  typedef kwsys::CommandLineArguments argT;
+
+  arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT,
+                  &some_int_variable, "Set some random int variable");
+  arg.AddArgument("--some-double-variable", argT::CONCAT_ARGUMENT,
+                  &some_double_variable, "Set some random double variable");
+  arg.AddArgument("--some-string-variable", argT::EQUAL_ARGUMENT,
+                  &some_string_variable, "Set some random string variable");
+  arg.AddArgument("--some-stl-string-variable", argT::EQUAL_ARGUMENT,
+                  &some_stl_string_variable,
+                  "Set some random stl string variable");
+  arg.AddArgument("--some-bool-variable", argT::EQUAL_ARGUMENT,
+                  &some_bool_variable, "Set some random bool variable");
+  arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT,
+                  &some_bool_variable1, "Set some random bool variable 1");
+  arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1,
+                         "Test AddBooleanArgument 1");
+  arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2,
+                         "Test AddBooleanArgument 2");
+  arg.AddArgument("--some-multi-argument", argT::MULTI_ARGUMENT,
+                  &numbers_argument, "Some multiple values variable");
+  arg.AddArgument("-N", argT::SPACE_ARGUMENT, &doubles_argument,
+                  "Some explicit multiple values variable");
+  arg.AddArgument("-BB", argT::CONCAT_ARGUMENT, &bools_argument,
+                  "Some explicit multiple values variable");
+  arg.AddArgument("-SS", argT::EQUAL_ARGUMENT, &strings_argument,
+                  "Some explicit multiple values variable");
+  arg.AddArgument("-SSS", argT::MULTI_ARGUMENT, &stl_strings_argument,
+                  "Some explicit multiple values variable");
+
+  arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr,
+                  "Some option -A. This option has a multiline comment. It "
+                  "should demonstrate how the code splits lines.");
+  arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr,
+                  "Option -B takes argument with space");
+  arg.AddCallback("-C", argT::EQUAL_ARGUMENT, argument, random_ptr,
+                  "Option -C takes argument after =");
+  arg.AddCallback("-D", argT::CONCAT_ARGUMENT, argument, random_ptr,
+                  "This option takes concatinated argument");
+  arg.AddCallback("--long1", argT::NO_ARGUMENT, argument, random_ptr, "-A");
+  arg.AddCallback("--long2", argT::SPACE_ARGUMENT, argument, random_ptr, "-B");
+  arg.AddCallback("--long3", argT::EQUAL_ARGUMENT, argument, random_ptr,
+                  "Same as -C but a bit different");
+  arg.AddCallback("--long4", argT::CONCAT_ARGUMENT, argument, random_ptr,
+                  "-C");
+
+  if (!arg.Parse()) {
+    std::cerr << "Problem parsing arguments" << std::endl;
+    res = 1;
+  }
+  std::cout << "Help: " << arg.GetHelp() << std::endl;
+
+  std::cout << "Some int variable was set to: " << some_int_variable
+            << std::endl;
+  std::cout << "Some double variable was set to: " << some_double_variable
+            << std::endl;
+  if (some_string_variable &&
+      strcmp(some_string_variable, "test string with space") == 0) {
+    std::cout << "Some string variable was set to: " << some_string_variable
+              << std::endl;
+    delete[] some_string_variable;
+  } else {
+    std::cerr << "Problem setting string variable" << std::endl;
+    res = 1;
+  }
+  size_t cc;
+#define CompareTwoLists(list1, list_valid, lsize)                             \
+  if (list1.size() != lsize) {                                                \
+    std::cerr << "Problem setting " #list1 ". Size is: " << list1.size()      \
+              << " should be: " << lsize << std::endl;                        \
+    res = 1;                                                                  \
+  } else {                                                                    \
+    std::cout << #list1 " argument set:";                                     \
+    for (cc = 0; cc < lsize; ++cc) {                                          \
+      std::cout << " " << list1[cc];                                          \
+      if (!CompareTwoItemsOnList(list1[cc], list_valid[cc])) {                \
+        std::cerr << "Problem setting " #list1 ". Value of " << cc            \
+                  << " is: [" << list1[cc] << "] <> [" << list_valid[cc]      \
+                  << "]" << std::endl;                                        \
+        res = 1;                                                              \
+        break;                                                                \
+      }                                                                       \
+    }                                                                         \
+    std::cout << std::endl;                                                   \
+  }
+
+  CompareTwoLists(numbers_argument, valid_numbers, 10);
+  CompareTwoLists(doubles_argument, valid_doubles, 3);
+  CompareTwoLists(bools_argument, valid_bools, 3);
+  CompareTwoLists(strings_argument, valid_strings, 4);
+  CompareTwoLists(stl_strings_argument, valid_stl_strings, 4);
+
+  std::cout << "Some STL String variable was set to: "
+            << some_stl_string_variable << std::endl;
+  std::cout << "Some bool variable was set to: " << some_bool_variable
+            << std::endl;
+  std::cout << "Some bool variable was set to: " << some_bool_variable1
+            << std::endl;
+  std::cout << "bool_arg1 variable was set to: " << bool_arg1 << std::endl;
+  std::cout << "bool_arg2 variable was set to: " << bool_arg2 << std::endl;
+  std::cout << std::endl;
+
+  for (cc = 0; cc < strings_argument.size(); ++cc) {
+    delete[] strings_argument[cc];
+    strings_argument[cc] = 0;
+  }
+  return res;
+}
diff --git a/thirdparty/KWSys/adios2sys/testCommandLineArguments1.cxx b/thirdparty/KWSys/adios2sys/testCommandLineArguments1.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5a03401bcda50479d4787167469af2d2a8e74b4a
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testCommandLineArguments1.cxx
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(CommandLineArguments.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "CommandLineArguments.hxx.in"
+#endif
+
+#include <iostream>
+#include <vector>
+
+#include <assert.h> /* assert */
+#include <string.h> /* strcmp */
+
+int testCommandLineArguments1(int argc, char* argv[])
+{
+  kwsys::CommandLineArguments arg;
+  arg.Initialize(argc, argv);
+
+  int n = 0;
+  char* m = 0;
+  std::string p;
+  int res = 0;
+
+  typedef kwsys::CommandLineArguments argT;
+  arg.AddArgument("-n", argT::SPACE_ARGUMENT, &n, "Argument N");
+  arg.AddArgument("-m", argT::EQUAL_ARGUMENT, &m, "Argument M");
+  arg.AddBooleanArgument("-p", &p, "Argument P");
+
+  arg.StoreUnusedArguments(true);
+
+  if (!arg.Parse()) {
+    std::cerr << "Problem parsing arguments" << std::endl;
+    res = 1;
+  }
+  if (n != 24) {
+    std::cout << "Problem setting N. Value of N: " << n << std::endl;
+    res = 1;
+  }
+  if (!m || strcmp(m, "test value") != 0) {
+    std::cout << "Problem setting M. Value of M: " << m << std::endl;
+    res = 1;
+  }
+  if (p != "1") {
+    std::cout << "Problem setting P. Value of P: " << p << std::endl;
+    res = 1;
+  }
+  std::cout << "Value of N: " << n << std::endl;
+  std::cout << "Value of M: " << m << std::endl;
+  std::cout << "Value of P: " << p << std::endl;
+  if (m) {
+    delete[] m;
+  }
+
+  char** newArgv = 0;
+  int newArgc = 0;
+  arg.GetUnusedArguments(&newArgc, &newArgv);
+  int cc;
+  const char* valid_unused_args[9] = { 0,
+                                       "--ignored",
+                                       "--second-ignored",
+                                       "third-ignored",
+                                       "some",
+                                       "junk",
+                                       "at",
+                                       "the",
+                                       "end" };
+  if (newArgc != 9) {
+    std::cerr << "Bad number of unused arguments: " << newArgc << std::endl;
+    res = 1;
+  }
+  for (cc = 0; cc < newArgc; ++cc) {
+    assert(newArgv[cc]); /* Quiet Clang scan-build. */
+    std::cout << "Unused argument[" << cc << "] = [" << newArgv[cc] << "]"
+              << std::endl;
+    if (cc >= 9) {
+      std::cerr << "Too many unused arguments: " << cc << std::endl;
+      res = 1;
+    } else if (valid_unused_args[cc] &&
+               strcmp(valid_unused_args[cc], newArgv[cc]) != 0) {
+      std::cerr << "Bad unused argument [" << cc << "] \"" << newArgv[cc]
+                << "\" should be: \"" << valid_unused_args[cc] << "\""
+                << std::endl;
+      res = 1;
+    }
+  }
+  arg.DeleteRemainingArguments(newArgc, &newArgv);
+
+  return res;
+}
diff --git a/thirdparty/KWSys/adios2sys/testConsoleBuf.cxx b/thirdparty/KWSys/adios2sys/testConsoleBuf.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3b8cdab69aae85eca1e09c076e8b60b08ea631ed
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testConsoleBuf.cxx
@@ -0,0 +1,788 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+
+// Ignore Windows version levels defined by command-line flags.  This
+// source needs access to all APIs available on the host in order for
+// the test to run properly.  The test binary is not installed anyway.
+#undef _WIN32_WINNT
+#undef NTDDI_VERSION
+
+#include KWSYS_HEADER(Encoding.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Encoding.hxx.in"
+#endif
+
+#if defined(_WIN32)
+
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <stdexcept>
+#include <string.h>
+#include <wchar.h>
+#include <windows.h>
+
+#include "testConsoleBuf.hxx"
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#define KWSYS_WINDOWS_DEPRECATED_GetVersion
+#endif
+// يونيكود
+static const WCHAR UnicodeInputTestString[] =
+  L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!";
+static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE;
+
+static const DWORD waitTimeout = 10 * 1000;
+static STARTUPINFO startupInfo;
+static PROCESS_INFORMATION processInfo;
+static HANDLE beforeInputEvent;
+static HANDLE afterOutputEvent;
+static std::string encodedInputTestString;
+static std::string encodedTestString;
+
+static void displayError(DWORD errorCode)
+{
+  std::cerr.setf(std::ios::hex, std::ios::basefield);
+  std::cerr << "Failed with error: 0x" << errorCode << "!" << std::endl;
+  LPWSTR message;
+  if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM,
+                     NULL, errorCode, 0, (LPWSTR)&message, 0, NULL)) {
+    std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message)
+              << std::endl;
+    HeapFree(GetProcessHeap(), 0, message);
+  } else {
+    std::cerr << "FormatMessage() failed with error: 0x" << GetLastError()
+              << "!" << std::endl;
+  }
+  std::cerr.unsetf(std::ios::hex);
+}
+
+std::basic_streambuf<char>* errstream(const char* unused)
+{
+  static_cast<void>(unused);
+  return std::cerr.rdbuf();
+}
+
+std::basic_streambuf<wchar_t>* errstream(const wchar_t* unused)
+{
+  static_cast<void>(unused);
+  return std::wcerr.rdbuf();
+}
+
+//----------------------------------------------------------------------------
+template <typename T>
+static void dumpBuffers(const T* expected, const T* received, size_t size)
+{
+  std::basic_ostream<T> err(errstream(expected));
+  err << "Expected output: '" << std::basic_string<T>(expected, size) << "'"
+      << std::endl;
+  if (err.fail()) {
+    err.clear();
+    err << "--- Error while outputting ---" << std::endl;
+  }
+  err << "Received output: '" << std::basic_string<T>(received, size) << "'"
+      << std::endl;
+  if (err.fail()) {
+    err.clear();
+    err << "--- Error while outputting ---" << std::endl;
+  }
+  std::cerr << "Expected output | Received output" << std::endl;
+  for (size_t i = 0; i < size; i++) {
+    std::cerr << std::setbase(16) << std::setfill('0') << "     "
+              << "0x" << std::setw(8) << static_cast<unsigned int>(expected[i])
+              << " | "
+              << "0x" << std::setw(8)
+              << static_cast<unsigned int>(received[i]);
+    if (static_cast<unsigned int>(expected[i]) !=
+        static_cast<unsigned int>(received[i])) {
+      std::cerr << "   MISMATCH!";
+    }
+    std::cerr << std::endl;
+  }
+  std::cerr << std::endl;
+}
+
+//----------------------------------------------------------------------------
+static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr)
+{
+  BOOL bInheritHandles = FALSE;
+  DWORD dwCreationFlags = 0;
+  memset(&processInfo, 0, sizeof(processInfo));
+  memset(&startupInfo, 0, sizeof(startupInfo));
+  startupInfo.cb = sizeof(startupInfo);
+  startupInfo.dwFlags = STARTF_USESHOWWINDOW;
+  startupInfo.wShowWindow = SW_HIDE;
+  if (hIn || hOut || hErr) {
+    startupInfo.dwFlags |= STARTF_USESTDHANDLES;
+    startupInfo.hStdInput = hIn;
+    startupInfo.hStdOutput = hOut;
+    startupInfo.hStdError = hErr;
+    bInheritHandles = TRUE;
+  }
+
+  WCHAR cmd[MAX_PATH];
+  if (GetModuleFileNameW(NULL, cmd, MAX_PATH) == 0) {
+    std::cerr << "GetModuleFileName failed!" << std::endl;
+    return false;
+  }
+  WCHAR* p = cmd + wcslen(cmd);
+  while (p > cmd && *p != L'\\')
+    p--;
+  *(p + 1) = 0;
+  wcscat(cmd, cmdConsoleBufChild);
+  wcscat(cmd, L".exe");
+
+  bool success =
+    CreateProcessW(NULL,            // No module name (use command line)
+                   cmd,             // Command line
+                   NULL,            // Process handle not inheritable
+                   NULL,            // Thread handle not inheritable
+                   bInheritHandles, // Set handle inheritance
+                   dwCreationFlags,
+                   NULL,         // Use parent's environment block
+                   NULL,         // Use parent's starting directory
+                   &startupInfo, // Pointer to STARTUPINFO structure
+                   &processInfo) !=
+    0; // Pointer to PROCESS_INFORMATION structure
+  if (!success) {
+    DWORD lastError = GetLastError();
+    std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) << ")"
+              << std::endl;
+    displayError(lastError);
+  }
+  return success;
+}
+
+//----------------------------------------------------------------------------
+static void finishProcess(bool success)
+{
+  if (success) {
+    success =
+      WaitForSingleObject(processInfo.hProcess, waitTimeout) == WAIT_OBJECT_0;
+  };
+  if (!success) {
+    TerminateProcess(processInfo.hProcess, 1);
+  }
+  CloseHandle(processInfo.hProcess);
+  CloseHandle(processInfo.hThread);
+}
+
+//----------------------------------------------------------------------------
+static bool createPipe(PHANDLE readPipe, PHANDLE writePipe)
+{
+  SECURITY_ATTRIBUTES securityAttributes;
+  securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+  securityAttributes.bInheritHandle = TRUE;
+  securityAttributes.lpSecurityDescriptor = NULL;
+  return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0 ? false
+                                                                      : true;
+}
+
+//----------------------------------------------------------------------------
+static void finishPipe(HANDLE readPipe, HANDLE writePipe)
+{
+  if (readPipe != INVALID_HANDLE_VALUE) {
+    CloseHandle(readPipe);
+  }
+  if (writePipe != INVALID_HANDLE_VALUE) {
+    CloseHandle(writePipe);
+  }
+}
+
+//----------------------------------------------------------------------------
+static HANDLE createFile(LPCWSTR fileName)
+{
+  SECURITY_ATTRIBUTES securityAttributes;
+  securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+  securityAttributes.bInheritHandle = TRUE;
+  securityAttributes.lpSecurityDescriptor = NULL;
+
+  HANDLE file =
+    CreateFileW(fileName, GENERIC_READ | GENERIC_WRITE,
+                0, // do not share
+                &securityAttributes,
+                CREATE_ALWAYS, // overwrite existing
+                FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+                NULL); // no template
+  if (file == INVALID_HANDLE_VALUE) {
+    DWORD lastError = GetLastError();
+    std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) << ")"
+              << std::endl;
+    displayError(lastError);
+  }
+  return file;
+}
+
+//----------------------------------------------------------------------------
+static void finishFile(HANDLE file)
+{
+  if (file != INVALID_HANDLE_VALUE) {
+    CloseHandle(file);
+  }
+}
+
+//----------------------------------------------------------------------------
+
+#ifndef MAPVK_VK_TO_VSC
+#define MAPVK_VK_TO_VSC (0)
+#endif
+
+static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr)
+{
+  inputBuffer[0].EventType = KEY_EVENT;
+  inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE;
+  inputBuffer[0].Event.KeyEvent.wRepeatCount = 1;
+  SHORT keyCode = VkKeyScanW(chr);
+  if (keyCode == -1) {
+    // Character can't be entered with current keyboard layout
+    // Just set any, it doesn't really matter
+    keyCode = 'K';
+  }
+  inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode);
+  inputBuffer[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(
+    inputBuffer[0].Event.KeyEvent.wVirtualKeyCode, MAPVK_VK_TO_VSC);
+  inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr;
+  inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0;
+  if ((HIBYTE(keyCode) & 1) == 1) {
+    inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
+  }
+  if ((HIBYTE(keyCode) & 2) == 2) {
+    inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
+  }
+  if ((HIBYTE(keyCode) & 4) == 4) {
+    inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
+  }
+  inputBuffer[1].EventType = inputBuffer[0].EventType;
+  inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE;
+  inputBuffer[1].Event.KeyEvent.wRepeatCount = 1;
+  inputBuffer[1].Event.KeyEvent.wVirtualKeyCode =
+    inputBuffer[0].Event.KeyEvent.wVirtualKeyCode;
+  inputBuffer[1].Event.KeyEvent.wVirtualScanCode =
+    inputBuffer[0].Event.KeyEvent.wVirtualScanCode;
+  inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar =
+    inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar;
+  inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0;
+}
+
+//----------------------------------------------------------------------------
+static int testPipe()
+{
+  int didFail = 1;
+  HANDLE inPipeRead = INVALID_HANDLE_VALUE;
+  HANDLE inPipeWrite = INVALID_HANDLE_VALUE;
+  HANDLE outPipeRead = INVALID_HANDLE_VALUE;
+  HANDLE outPipeWrite = INVALID_HANDLE_VALUE;
+  HANDLE errPipeRead = INVALID_HANDLE_VALUE;
+  HANDLE errPipeWrite = INVALID_HANDLE_VALUE;
+  UINT currentCodepage = GetConsoleCP();
+  char buffer[200];
+  char buffer2[200];
+  try {
+    if (!createPipe(&inPipeRead, &inPipeWrite) ||
+        !createPipe(&outPipeRead, &outPipeWrite) ||
+        !createPipe(&errPipeRead, &errPipeWrite)) {
+      throw std::runtime_error("createFile failed!");
+    }
+    if (TestCodepage == CP_ACP) {
+      TestCodepage = GetACP();
+    }
+    if (!SetConsoleCP(TestCodepage)) {
+      throw std::runtime_error("SetConsoleCP failed!");
+    }
+
+    DWORD bytesWritten = 0;
+    if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(),
+                   (DWORD)encodedInputTestString.size(), &bytesWritten,
+                   NULL) ||
+        bytesWritten == 0) {
+      throw std::runtime_error("WriteFile failed!");
+    }
+
+    if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) {
+      try {
+        DWORD status;
+        if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
+            WAIT_OBJECT_0) {
+          std::cerr.setf(std::ios::hex, std::ios::basefield);
+          std::cerr << "WaitForSingleObject returned unexpected status 0x"
+                    << status << std::endl;
+          std::cerr.unsetf(std::ios::hex);
+          throw std::runtime_error("WaitForSingleObject failed!");
+        }
+        DWORD bytesRead = 0;
+        if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, NULL) ||
+            bytesRead == 0) {
+          throw std::runtime_error("ReadFile#1 failed!");
+        }
+        buffer[bytesRead] = 0;
+        if ((bytesRead <
+               encodedTestString.size() + 1 + encodedInputTestString.size() &&
+             !ReadFile(outPipeRead, buffer + bytesRead,
+                       sizeof(buffer) - bytesRead, &bytesRead, NULL)) ||
+            bytesRead == 0) {
+          throw std::runtime_error("ReadFile#2 failed!");
+        }
+        if (memcmp(buffer, encodedTestString.c_str(),
+                   encodedTestString.size()) == 0 &&
+            memcmp(buffer + encodedTestString.size() + 1,
+                   encodedInputTestString.c_str(),
+                   encodedInputTestString.size()) == 0) {
+          bytesRead = 0;
+          if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead,
+                        NULL) ||
+              bytesRead == 0) {
+            throw std::runtime_error("ReadFile#3 failed!");
+          }
+          buffer2[bytesRead] = 0;
+          didFail =
+            encodedTestString.compare(0, encodedTestString.npos, buffer2,
+                                      encodedTestString.size()) == 0
+            ? 0
+            : 1;
+        }
+        if (didFail != 0) {
+          std::cerr << "Pipe's output didn't match expected output!"
+                    << std::endl;
+          dumpBuffers<char>(encodedTestString.c_str(), buffer,
+                            encodedTestString.size());
+          dumpBuffers<char>(encodedInputTestString.c_str(),
+                            buffer + encodedTestString.size() + 1,
+                            encodedInputTestString.size());
+          dumpBuffers<char>(encodedTestString.c_str(), buffer2,
+                            encodedTestString.size());
+        }
+      } catch (const std::runtime_error& ex) {
+        DWORD lastError = GetLastError();
+        std::cerr << "In function testPipe, line " << __LINE__ << ": "
+                  << ex.what() << std::endl;
+        displayError(lastError);
+      }
+      finishProcess(didFail == 0);
+    }
+  } catch (const std::runtime_error& ex) {
+    DWORD lastError = GetLastError();
+    std::cerr << "In function testPipe, line " << __LINE__ << ": " << ex.what()
+              << std::endl;
+    displayError(lastError);
+  }
+  finishPipe(inPipeRead, inPipeWrite);
+  finishPipe(outPipeRead, outPipeWrite);
+  finishPipe(errPipeRead, errPipeWrite);
+  SetConsoleCP(currentCodepage);
+  return didFail;
+}
+
+//----------------------------------------------------------------------------
+static int testFile()
+{
+  int didFail = 1;
+  HANDLE inFile = INVALID_HANDLE_VALUE;
+  HANDLE outFile = INVALID_HANDLE_VALUE;
+  HANDLE errFile = INVALID_HANDLE_VALUE;
+  try {
+    if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE ||
+        (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE ||
+        (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) {
+      throw std::runtime_error("createFile failed!");
+    }
+    DWORD bytesWritten = 0;
+    char buffer[200];
+    char buffer2[200];
+
+    int length;
+    if ((length =
+           WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1,
+                               buffer, sizeof(buffer), NULL, NULL)) == 0) {
+      throw std::runtime_error("WideCharToMultiByte failed!");
+    }
+    buffer[length - 1] = '\n';
+    if (!WriteFile(inFile, buffer, length, &bytesWritten, NULL) ||
+        bytesWritten == 0) {
+      throw std::runtime_error("WriteFile failed!");
+    }
+    if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
+      throw std::runtime_error("SetFilePointer failed!");
+    }
+
+    if (createProcess(inFile, outFile, errFile)) {
+      DWORD bytesRead = 0;
+      try {
+        DWORD status;
+        if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
+            WAIT_OBJECT_0) {
+          std::cerr.setf(std::ios::hex, std::ios::basefield);
+          std::cerr << "WaitForSingleObject returned unexpected status 0x"
+                    << status << std::endl;
+          std::cerr.unsetf(std::ios::hex);
+          throw std::runtime_error("WaitForSingleObject failed!");
+        }
+        if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) ==
+            INVALID_SET_FILE_POINTER) {
+          throw std::runtime_error("SetFilePointer#1 failed!");
+        }
+        if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, NULL) ||
+            bytesRead == 0) {
+          throw std::runtime_error("ReadFile#1 failed!");
+        }
+        buffer[bytesRead] = 0;
+        if (memcmp(buffer, encodedTestString.c_str(),
+                   encodedTestString.size()) == 0 &&
+            memcmp(buffer + encodedTestString.size() + 1,
+                   encodedInputTestString.c_str(),
+                   encodedInputTestString.size()) == 0) {
+          bytesRead = 0;
+          if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) ==
+              INVALID_SET_FILE_POINTER) {
+            throw std::runtime_error("SetFilePointer#2 failed!");
+          }
+
+          if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, NULL) ||
+              bytesRead == 0) {
+            throw std::runtime_error("ReadFile#2 failed!");
+          }
+          buffer2[bytesRead] = 0;
+          didFail =
+            encodedTestString.compare(0, encodedTestString.npos, buffer2,
+                                      encodedTestString.size()) == 0
+            ? 0
+            : 1;
+        }
+        if (didFail != 0) {
+          std::cerr << "File's output didn't match expected output!"
+                    << std::endl;
+          dumpBuffers<char>(encodedTestString.c_str(), buffer,
+                            encodedTestString.size());
+          dumpBuffers<char>(encodedInputTestString.c_str(),
+                            buffer + encodedTestString.size() + 1,
+                            encodedInputTestString.size());
+          dumpBuffers<char>(encodedTestString.c_str(), buffer2,
+                            encodedTestString.size());
+        }
+      } catch (const std::runtime_error& ex) {
+        DWORD lastError = GetLastError();
+        std::cerr << "In function testFile, line " << __LINE__ << ": "
+                  << ex.what() << std::endl;
+        displayError(lastError);
+      }
+      finishProcess(didFail == 0);
+    }
+  } catch (const std::runtime_error& ex) {
+    DWORD lastError = GetLastError();
+    std::cerr << "In function testFile, line " << __LINE__ << ": " << ex.what()
+              << std::endl;
+    displayError(lastError);
+  }
+  finishFile(inFile);
+  finishFile(outFile);
+  finishFile(errFile);
+  return didFail;
+}
+
+#ifndef _WIN32_WINNT_VISTA
+#define _WIN32_WINNT_VISTA 0x0600
+#endif
+
+//----------------------------------------------------------------------------
+static int testConsole()
+{
+  int didFail = 1;
+  HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE);
+  HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE);
+  HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE);
+  HANDLE hIn = parentIn;
+  HANDLE hOut = parentOut;
+  DWORD consoleMode;
+  bool newConsole = false;
+  bool forceNewConsole = false;
+  bool restoreConsole = false;
+  LPCWSTR TestFaceName = L"Lucida Console";
+  const DWORD TestFontFamily = 0x00000036;
+  const DWORD TestFontSize = 0x000c0000;
+  HKEY hConsoleKey;
+  WCHAR FaceName[200];
+  FaceName[0] = 0;
+  DWORD FaceNameSize = sizeof(FaceName);
+  DWORD FontFamily = TestFontFamily;
+  DWORD FontSize = TestFontSize;
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
+#pragma warning(push)
+#ifdef __INTEL_COMPILER
+#pragma warning(disable : 1478)
+#else
+#pragma warning(disable : 4996)
+#endif
+#endif
+  const bool isVistaOrGreater =
+    LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
+#pragma warning(pop)
+#endif
+  if (!isVistaOrGreater) {
+    if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
+                      &hConsoleKey) == ERROR_SUCCESS) {
+      DWORD dwordSize = sizeof(DWORD);
+      if (RegQueryValueExW(hConsoleKey, L"FontFamily", NULL, NULL,
+                           (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) {
+        if (FontFamily != TestFontFamily) {
+          RegQueryValueExW(hConsoleKey, L"FaceName", NULL, NULL,
+                           (LPBYTE)FaceName, &FaceNameSize);
+          RegQueryValueExW(hConsoleKey, L"FontSize", NULL, NULL,
+                           (LPBYTE)&FontSize, &dwordSize);
+
+          RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
+                         (BYTE*)&TestFontFamily, sizeof(TestFontFamily));
+          RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
+                         (BYTE*)TestFaceName,
+                         (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR)));
+          RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
+                         (BYTE*)&TestFontSize, sizeof(TestFontSize));
+
+          restoreConsole = true;
+          forceNewConsole = true;
+        }
+      } else {
+        std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl;
+      }
+      RegCloseKey(hConsoleKey);
+    } else {
+      std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!"
+                << std::endl;
+    }
+  }
+  if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) {
+    // Not a real console, let's create new one.
+    FreeConsole();
+    if (!AllocConsole()) {
+      std::cerr << "AllocConsole failed!" << std::endl;
+      return didFail;
+    }
+    SECURITY_ATTRIBUTES securityAttributes;
+    securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+    securityAttributes.bInheritHandle = TRUE;
+    securityAttributes.lpSecurityDescriptor = NULL;
+    hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE,
+                      FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
+                      OPEN_EXISTING, 0, NULL);
+    if (hIn == INVALID_HANDLE_VALUE) {
+      DWORD lastError = GetLastError();
+      std::cerr << "CreateFile(CONIN$)" << std::endl;
+      displayError(lastError);
+    }
+    hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
+                       OPEN_EXISTING, 0, NULL);
+    if (hOut == INVALID_HANDLE_VALUE) {
+      DWORD lastError = GetLastError();
+      std::cerr << "CreateFile(CONOUT$)" << std::endl;
+      displayError(lastError);
+    }
+    SetStdHandle(STD_INPUT_HANDLE, hIn);
+    SetStdHandle(STD_OUTPUT_HANDLE, hOut);
+    SetStdHandle(STD_ERROR_HANDLE, hOut);
+    newConsole = true;
+  }
+
+#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
+  if (isVistaOrGreater) {
+    CONSOLE_FONT_INFOEX consoleFont;
+    memset(&consoleFont, 0, sizeof(consoleFont));
+    consoleFont.cbSize = sizeof(consoleFont);
+    HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
+    typedef BOOL(WINAPI * GetCurrentConsoleFontExFunc)(
+      HANDLE hConsoleOutput, BOOL bMaximumWindow,
+      PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
+    typedef BOOL(WINAPI * SetCurrentConsoleFontExFunc)(
+      HANDLE hConsoleOutput, BOOL bMaximumWindow,
+      PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
+    GetCurrentConsoleFontExFunc getConsoleFont =
+      (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
+                                                  "GetCurrentConsoleFontEx");
+    SetCurrentConsoleFontExFunc setConsoleFont =
+      (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
+                                                  "SetCurrentConsoleFontEx");
+    if (getConsoleFont(hOut, FALSE, &consoleFont)) {
+      if (consoleFont.FontFamily != TestFontFamily) {
+        consoleFont.FontFamily = TestFontFamily;
+        wcscpy(consoleFont.FaceName, TestFaceName);
+        if (!setConsoleFont(hOut, FALSE, &consoleFont)) {
+          std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl;
+        }
+      }
+    } else {
+      std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl;
+    }
+  } else {
+#endif
+    if (restoreConsole &&
+        RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_WRITE,
+                      &hConsoleKey) == ERROR_SUCCESS) {
+      RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
+                     (BYTE*)&FontFamily, sizeof(FontFamily));
+      if (FaceName[0] != 0) {
+        RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, (BYTE*)FaceName,
+                       FaceNameSize);
+      } else {
+        RegDeleteValueW(hConsoleKey, L"FaceName");
+      }
+      RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE*)&FontSize,
+                     sizeof(FontSize));
+      RegCloseKey(hConsoleKey);
+    }
+#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
+  }
+#endif
+
+  if (createProcess(NULL, NULL, NULL)) {
+    try {
+      DWORD status;
+      if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) !=
+          WAIT_OBJECT_0) {
+        std::cerr.setf(std::ios::hex, std::ios::basefield);
+        std::cerr << "WaitForSingleObject returned unexpected status 0x"
+                  << status << std::endl;
+        std::cerr.unsetf(std::ios::hex);
+        throw std::runtime_error("WaitForSingleObject#1 failed!");
+      }
+      INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) /
+                                sizeof(UnicodeInputTestString[0])) *
+                               2];
+      memset(&inputBuffer, 0, sizeof(inputBuffer));
+      unsigned int i;
+      for (i = 0; i < (sizeof(UnicodeInputTestString) /
+                         sizeof(UnicodeInputTestString[0]) -
+                       1);
+           i++) {
+        writeInputKeyEvent(&inputBuffer[i * 2], UnicodeInputTestString[i]);
+      }
+      writeInputKeyEvent(&inputBuffer[i * 2], VK_RETURN);
+      DWORD eventsWritten = 0;
+      // We need to wait a bit before writing to console so child process have
+      // started waiting for input on stdin.
+      Sleep(300);
+      if (!WriteConsoleInputW(hIn, inputBuffer,
+                              sizeof(inputBuffer) / sizeof(inputBuffer[0]),
+                              &eventsWritten) ||
+          eventsWritten == 0) {
+        throw std::runtime_error("WriteConsoleInput failed!");
+      }
+      if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
+          WAIT_OBJECT_0) {
+        std::cerr.setf(std::ios::hex, std::ios::basefield);
+        std::cerr << "WaitForSingleObject returned unexpected status 0x"
+                  << status << std::endl;
+        std::cerr.unsetf(std::ios::hex);
+        throw std::runtime_error("WaitForSingleObject#2 failed!");
+      }
+      CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
+      if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) {
+        throw std::runtime_error("GetConsoleScreenBufferInfo failed!");
+      }
+
+      COORD coord;
+      DWORD charsRead = 0;
+      coord.X = 0;
+      coord.Y = screenBufferInfo.dwCursorPosition.Y - 4;
+      WCHAR* outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4];
+      if (!ReadConsoleOutputCharacterW(hOut, outputBuffer,
+                                       screenBufferInfo.dwSize.X * 4, coord,
+                                       &charsRead) ||
+          charsRead == 0) {
+        delete[] outputBuffer;
+        throw std::runtime_error("ReadConsoleOutputCharacter failed!");
+      }
+      std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString);
+      std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' ');
+      std::wstring wideInputTestString =
+        kwsys::Encoding::ToWide(encodedInputTestString);
+      if (memcmp(outputBuffer, wideTestString.c_str(),
+                 wideTestString.size() * sizeof(wchar_t)) == 0 &&
+          memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1,
+                 wideTestString.c_str(),
+                 wideTestString.size() * sizeof(wchar_t)) == 0 &&
+          memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2,
+                 UnicodeInputTestString,
+                 sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 &&
+          memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3,
+                 wideInputTestString.c_str(),
+                 (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0) {
+        didFail = 0;
+      } else {
+        std::cerr << "Console's output didn't match expected output!"
+                  << std::endl;
+        dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer,
+                             wideTestString.size());
+        dumpBuffers<wchar_t>(wideTestString.c_str(),
+                             outputBuffer + screenBufferInfo.dwSize.X * 1,
+                             wideTestString.size());
+        dumpBuffers<wchar_t>(
+          UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2,
+          (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR));
+        dumpBuffers<wchar_t>(wideInputTestString.c_str(),
+                             outputBuffer + screenBufferInfo.dwSize.X * 3,
+                             wideInputTestString.size() - 1);
+      }
+      delete[] outputBuffer;
+    } catch (const std::runtime_error& ex) {
+      DWORD lastError = GetLastError();
+      std::cerr << "In function testConsole, line " << __LINE__ << ": "
+                << ex.what() << std::endl;
+      displayError(lastError);
+    }
+    finishProcess(didFail == 0);
+  }
+  if (newConsole) {
+    SetStdHandle(STD_INPUT_HANDLE, parentIn);
+    SetStdHandle(STD_OUTPUT_HANDLE, parentOut);
+    SetStdHandle(STD_ERROR_HANDLE, parentErr);
+    CloseHandle(hIn);
+    CloseHandle(hOut);
+    FreeConsole();
+  }
+  return didFail;
+}
+
+#endif
+
+//----------------------------------------------------------------------------
+int testConsoleBuf(int, char* [])
+{
+  int ret = 0;
+
+#if defined(_WIN32)
+  beforeInputEvent = CreateEventW(NULL,
+                                  FALSE, // auto-reset event
+                                  FALSE, // initial state is nonsignaled
+                                  BeforeInputEventName); // object name
+  if (!beforeInputEvent) {
+    std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl;
+    return 1;
+  }
+
+  afterOutputEvent = CreateEventW(NULL, FALSE, FALSE, AfterOutputEventName);
+  if (!afterOutputEvent) {
+    std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl;
+    return 1;
+  }
+
+  encodedTestString = kwsys::Encoding::ToNarrow(std::wstring(
+    UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1));
+  encodedInputTestString = kwsys::Encoding::ToNarrow(
+    std::wstring(UnicodeInputTestString,
+                 sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1));
+  encodedInputTestString += "\n";
+
+  ret |= testPipe();
+  ret |= testFile();
+  ret |= testConsole();
+
+  CloseHandle(beforeInputEvent);
+  CloseHandle(afterOutputEvent);
+#endif
+
+  return ret;
+}
diff --git a/thirdparty/KWSys/adios2sys/testConsoleBuf.hxx b/thirdparty/KWSys/adios2sys/testConsoleBuf.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..e93cb4f0a1c0211fb3118ced44116a46f41051fa
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testConsoleBuf.hxx
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef testConsoleBuf_hxx
+#define testConsoleBuf_hxx
+
+static const wchar_t cmdConsoleBufChild[] = L"testConsoleBufChild";
+
+static const wchar_t BeforeInputEventName[] = L"BeforeInputEvent";
+static const wchar_t AfterOutputEventName[] = L"AfterOutputEvent";
+
+// यूनिकोड είναι здорово!
+static const wchar_t UnicodeTestString[] =
+  L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 "
+  L"\u03B5\u03AF\u03BD\0\u03B1\u03B9 "
+  L"\u0437\u0434\u043E\u0440\u043E\u0432\u043E!";
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/testConsoleBufChild.cxx b/thirdparty/KWSys/adios2sys/testConsoleBufChild.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..83bf545c536b85f029d3b0ba6c3639405784aaa9
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testConsoleBufChild.cxx
@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+
+#include KWSYS_HEADER(ConsoleBuf.hxx)
+#include KWSYS_HEADER(Encoding.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "ConsoleBuf.hxx.in"
+#include "Encoding.hxx.in"
+#endif
+
+#include <iostream>
+
+#include "testConsoleBuf.hxx"
+
+//----------------------------------------------------------------------------
+int main(int argc, const char* argv[])
+{
+#if defined(_WIN32)
+  kwsys::ConsoleBuf::Manager out(std::cout);
+  kwsys::ConsoleBuf::Manager err(std::cerr, true);
+  kwsys::ConsoleBuf::Manager in(std::cin);
+
+  if (argc > 1) {
+    std::cout << argv[1] << std::endl;
+    std::cerr << argv[1] << std::endl;
+  } else {
+    std::string str = kwsys::Encoding::ToNarrow(std::wstring(
+      UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1));
+    std::cout << str << std::endl;
+    std::cerr << str << std::endl;
+  }
+
+  std::string input;
+  HANDLE event = OpenEventW(EVENT_MODIFY_STATE, FALSE, BeforeInputEventName);
+  if (event) {
+    SetEvent(event);
+    CloseHandle(event);
+  }
+
+  std::cin >> input;
+  std::cout << input << std::endl;
+  event = OpenEventW(EVENT_MODIFY_STATE, FALSE, AfterOutputEventName);
+  if (event) {
+    SetEvent(event);
+    CloseHandle(event);
+  }
+#else
+  static_cast<void>(argc);
+  static_cast<void>(argv);
+#endif
+  return 0;
+}
diff --git a/thirdparty/KWSys/adios2sys/testDynamicLoader.cxx b/thirdparty/KWSys/adios2sys/testDynamicLoader.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b52ddda8bdbd2d8bfea8970126671982901e0e11
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testDynamicLoader.cxx
@@ -0,0 +1,117 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+
+#include KWSYS_HEADER(DynamicLoader.hxx)
+
+#if defined(__BEOS__) || defined(__HAIKU__)
+#include <be/kernel/OS.h> /* disable_debugger() API. */
+#endif
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "DynamicLoader.hxx.in"
+#endif
+
+#include <iostream>
+#include <string>
+
+// Include with <> instead of "" to avoid getting any in-source copy
+// left on disk.
+#include <testSystemTools.h>
+
+static std::string GetLibName(const char* lname)
+{
+  // Construct proper name of lib
+  std::string slname;
+  slname = EXECUTABLE_OUTPUT_PATH;
+#ifdef CMAKE_INTDIR
+  slname += "/";
+  slname += CMAKE_INTDIR;
+#endif
+  slname += "/";
+  slname += kwsys::DynamicLoader::LibPrefix();
+  slname += lname;
+  slname += kwsys::DynamicLoader::LibExtension();
+
+  return slname;
+}
+
+/* libname = Library name (proper prefix, proper extension)
+ * System  = symbol to lookup in libname
+ * r1: should OpenLibrary succeed ?
+ * r2: should GetSymbolAddress succeed ?
+ * r3: should CloseLibrary succeed ?
+ */
+static int TestDynamicLoader(const char* libname, const char* symbol, int r1,
+                             int r2, int r3)
+{
+  std::cerr << "Testing: " << libname << std::endl;
+  kwsys::DynamicLoader::LibraryHandle l =
+    kwsys::DynamicLoader::OpenLibrary(libname);
+  // If result is incompatible with expectation just fails (xor):
+  if ((r1 && !l) || (!r1 && l)) {
+    std::cerr << 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;
+    return 1;
+  }
+#ifndef __APPLE__
+  int s = kwsys::DynamicLoader::CloseLibrary(l);
+  if ((r3 && !s) || (!r3 && s)) {
+    std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+    return 1;
+  }
+#else
+  (void)r3;
+#endif
+  return 0;
+}
+
+int testDynamicLoader(int argc, char* argv[])
+{
+#if defined(_WIN32)
+  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+#elif defined(__BEOS__) || defined(__HAIKU__)
+  disable_debugger(1);
+#endif
+  int res = 0;
+  if (argc == 3) {
+    // User specify a libname and symbol to check.
+    res = TestDynamicLoader(argv[1], argv[2], 1, 1, 1);
+    return res;
+  }
+
+// dlopen() on Syllable before 11/22/2007 doesn't return 0 on error
+#ifndef __SYLLABLE__
+  // Make sure that inexistent lib is giving correct result
+  res += TestDynamicLoader("azerty_", "foo_bar", 0, 0, 0);
+  // Make sure that random binary file cannot be assimilated as dylib
+  res += TestDynamicLoader(TEST_SYSTEMTOOLS_SOURCE_DIR "/testSystemTools.bin",
+                           "wp", 0, 0, 0);
+#endif
+
+#ifdef __linux__
+  // This one is actually fun to test, since dlopen is by default
+  // loaded...wonder why :)
+  res += TestDynamicLoader("foobar.lib", "dlopen", 0, 1, 0);
+  res += TestDynamicLoader("libdl.so", "dlopen", 1, 1, 1);
+  res += TestDynamicLoader("libdl.so", "TestDynamicLoader", 1, 0, 1);
+#endif
+  // Now try on the generated library
+  std::string libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynload");
+  res += TestDynamicLoader(libname.c_str(), "dummy", 1, 0, 1);
+  res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderSymbolPointer",
+                           1, 1, 1);
+  res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderSymbolPointer",
+                           1, 0, 1);
+  res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1);
+  res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1);
+
+  return res;
+}
diff --git a/thirdparty/KWSys/adios2sys/testDynload.c b/thirdparty/KWSys/adios2sys/testDynload.c
new file mode 100644
index 0000000000000000000000000000000000000000..cdb9e5c3580474104d9ea92f21191a9681c45102
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testDynload.c
@@ -0,0 +1,13 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifdef _WIN32
+#define DL_EXPORT __declspec(dllexport)
+#else
+#define DL_EXPORT
+#endif
+
+DL_EXPORT int TestDynamicLoaderData = 0;
+
+DL_EXPORT void TestDynamicLoaderSymbolPointer()
+{
+}
diff --git a/thirdparty/KWSys/adios2sys/testEncode.c b/thirdparty/KWSys/adios2sys/testEncode.c
new file mode 100644
index 0000000000000000000000000000000000000000..a20d46fd3bf5ab8ecc32dee55433db6868679c1e
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testEncode.c
@@ -0,0 +1,67 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(MD5.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "MD5.h.in"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+static const unsigned char testMD5input1[] =
+  "  A quick brown fox jumps over the lazy dog.\n"
+  "  This is sample text for MD5 sum input.\n";
+static const char testMD5output1[] = "8f146af46ed4f267921bb937d4d3500c";
+
+static const int testMD5input2len = 28;
+static const unsigned char testMD5input2[] = "the cow jumped over the moon";
+static const char testMD5output2[] = "a2ad137b746138fae4e5adca9c85d3ae";
+
+static int testMD5_1(kwsysMD5* md5)
+{
+  char md5out[33];
+  kwsysMD5_Initialize(md5);
+  kwsysMD5_Append(md5, testMD5input1, -1);
+  kwsysMD5_FinalizeHex(md5, md5out);
+  md5out[32] = 0;
+  printf("md5sum 1: expected [%s]\n"
+         "               got [%s]\n",
+         testMD5output1, md5out);
+  return (strcmp(md5out, testMD5output1) != 0) ? 1 : 0;
+}
+
+static int testMD5_2(kwsysMD5* md5)
+{
+  unsigned char digest[16];
+  char md5out[33];
+  kwsysMD5_Initialize(md5);
+  kwsysMD5_Append(md5, testMD5input2, testMD5input2len);
+  kwsysMD5_Finalize(md5, digest);
+  kwsysMD5_DigestToHex(digest, md5out);
+  md5out[32] = 0;
+  printf("md5sum 2: expected [%s]\n"
+         "               got [%s]\n",
+         testMD5output2, md5out);
+  return (strcmp(md5out, testMD5output2) != 0) ? 1 : 0;
+}
+
+int testEncode(int argc, char* argv[])
+{
+  int result = 0;
+  (void)argc;
+  (void)argv;
+
+  /* Test MD5 digest.  */
+  {
+    kwsysMD5* md5 = kwsysMD5_New();
+    result |= testMD5_1(md5);
+    result |= testMD5_2(md5);
+    kwsysMD5_Delete(md5);
+  }
+
+  return result;
+}
diff --git a/thirdparty/KWSys/adios2sys/testEncoding.cxx b/thirdparty/KWSys/adios2sys/testEncoding.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..457e8a896ec3b3ffb32ec77fad58bd37ab80f820
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testEncoding.cxx
@@ -0,0 +1,284 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable : 4786)
+#endif
+
+#include KWSYS_HEADER(Encoding.hxx)
+#include KWSYS_HEADER(Encoding.h)
+
+#include <algorithm>
+#include <iostream>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Encoding.h.in"
+#include "Encoding.hxx.in"
+#endif
+
+//----------------------------------------------------------------------------
+static const unsigned char helloWorldStrings[][32] = {
+  // English
+  { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 0 },
+  // Japanese
+  { 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0xAB, 0xE3, 0x81,
+    0xA1, 0xE3, 0x81, 0xAF, 0xE4, 0xB8, 0x96, 0xE7, 0x95, 0x8C, 0 },
+  // Arabic
+  { 0xD9, 0x85, 0xD8, 0xB1, 0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xA7, 0x20, 0xD8,
+    0xA7, 0xD9, 0x84, 0xD8, 0xB9, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x85, 0 },
+  // Yiddish
+  { 0xD7, 0x94, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x90, 0x20, 0xD7,
+    0x95, 0xD7, 0x95, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x98, 0 },
+  // Russian
+  { 0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0, 0xB5,
+    0xD1, 0x82, 0x20, 0xD0, 0xBC, 0xD0, 0xB8, 0xD1, 0x80, 0 },
+  // Latin
+  { 0x4D, 0x75, 0x6E, 0x64, 0x75, 0x73, 0x20, 0x73, 0x61, 0x6C, 0x76, 0x65,
+    0 },
+  // Swahili
+  { 0x68, 0x75, 0x6A, 0x61, 0x6D, 0x62, 0x6F, 0x20, 0x44, 0x75, 0x6E, 0x69,
+    0x61, 0 },
+  // Icelandic
+  { 0x48, 0x61, 0x6C, 0x6C, 0xC3, 0xB3, 0x20, 0x68, 0x65, 0x69, 0x6D, 0x75,
+    0x72, 0 },
+  { 0 }
+};
+
+//----------------------------------------------------------------------------
+static int testHelloWorldEncoding()
+{
+  int ret = 0;
+  for (int i = 0; helloWorldStrings[i][0] != 0; i++) {
+    std::string str = reinterpret_cast<const char*>(helloWorldStrings[i]);
+    std::cout << str << std::endl;
+    std::wstring wstr = kwsys::Encoding::ToWide(str);
+    std::string str2 = kwsys::Encoding::ToNarrow(wstr);
+    wchar_t* c_wstr = kwsysEncoding_DupToWide(str.c_str());
+    char* c_str2 = kwsysEncoding_DupToNarrow(c_wstr);
+    if (!wstr.empty() && (str != str2 || strcmp(c_str2, str.c_str()))) {
+      std::cout << "converted string was different: " << str2 << std::endl;
+      std::cout << "converted string was different: " << c_str2 << std::endl;
+      ret++;
+    }
+    free(c_wstr);
+    free(c_str2);
+  }
+  return ret;
+}
+
+static int testRobustEncoding()
+{
+  // test that the conversion functions handle invalid
+  // unicode correctly/gracefully
+
+  int ret = 0;
+  char cstr[] = { (char)-1, 0 };
+  // this conversion could fail
+  std::wstring wstr = kwsys::Encoding::ToWide(cstr);
+
+  wstr = kwsys::Encoding::ToWide(NULL);
+  if (wstr != L"") {
+    const wchar_t* wcstr = wstr.c_str();
+    std::cout << "ToWide(NULL) returned";
+    for (size_t i = 0; i < wstr.size(); i++) {
+      std::cout << " " << std::hex << (int)wcstr[i];
+    }
+    std::cout << std::endl;
+    ret++;
+  }
+  wstr = kwsys::Encoding::ToWide("");
+  if (wstr != L"") {
+    const wchar_t* wcstr = wstr.c_str();
+    std::cout << "ToWide(\"\") returned";
+    for (size_t i = 0; i < wstr.size(); i++) {
+      std::cout << " " << std::hex << (int)wcstr[i];
+    }
+    std::cout << std::endl;
+    ret++;
+  }
+
+#ifdef _WIN32
+  // 16 bit wchar_t - we make an invalid surrogate pair
+  wchar_t cwstr[] = { 0xD801, 0xDA00, 0 };
+  // this conversion could fail
+  std::string win_str = kwsys::Encoding::ToNarrow(cwstr);
+#endif
+
+  std::string str = kwsys::Encoding::ToNarrow(NULL);
+  if (str != "") {
+    std::cout << "ToNarrow(NULL) returned " << str << std::endl;
+    ret++;
+  }
+
+  str = kwsys::Encoding::ToNarrow(L"");
+  if (wstr != L"") {
+    std::cout << "ToNarrow(\"\") returned " << str << std::endl;
+    ret++;
+  }
+
+  return ret;
+}
+
+static int testWithNulls()
+{
+  int ret = 0;
+  std::vector<std::string> strings;
+  strings.push_back(std::string("ab") + '\0' + 'c');
+  strings.push_back(std::string("d") + '\0' + '\0' + 'e');
+  strings.push_back(std::string() + '\0' + 'f');
+  strings.push_back(std::string() + '\0' + '\0' + "gh");
+  strings.push_back(std::string("ij") + '\0');
+  strings.push_back(std::string("k") + '\0' + '\0');
+  strings.push_back(std::string("\0\0\0\0", 4) + "lmn" +
+                    std::string("\0\0\0\0", 4));
+  for (std::vector<std::string>::iterator it = strings.begin();
+       it != strings.end(); ++it) {
+    std::wstring wstr = kwsys::Encoding::ToWide(*it);
+    std::string str = kwsys::Encoding::ToNarrow(wstr);
+    std::string s(*it);
+    std::replace(s.begin(), s.end(), '\0', ' ');
+    std::cout << "'" << s << "' (" << it->size() << ")" << std::endl;
+    if (str != *it) {
+      std::replace(str.begin(), str.end(), '\0', ' ');
+      std::cout << "string with null was different: '" << str << "' ("
+                << str.size() << ")" << std::endl;
+      ret++;
+    }
+  }
+  return ret;
+}
+
+static int testCommandLineArguments()
+{
+  int status = 0;
+
+  char const* argv[2] = { "./app.exe", (char const*)helloWorldStrings[1] };
+
+  kwsys::Encoding::CommandLineArguments args(2, argv);
+  kwsys::Encoding::CommandLineArguments arg2 =
+    kwsys::Encoding::CommandLineArguments(args);
+
+  char const* const* u8_argv = args.argv();
+  for (int i = 0; i < args.argc(); i++) {
+    char const* u8_arg = u8_argv[i];
+    if (strcmp(argv[i], u8_arg) != 0) {
+      std::cout << "argv[" << i << "] " << argv[i] << " != " << u8_arg
+                << std::endl;
+      status++;
+    }
+  }
+
+  kwsys::Encoding::CommandLineArguments args3 =
+    kwsys::Encoding::CommandLineArguments::Main(2, argv);
+
+  return status;
+}
+
+static int testToWindowsExtendedPath()
+{
+#ifdef _WIN32
+  int ret = 0;
+  if (kwsys::Encoding::ToWindowsExtendedPath(
+        "L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
+      L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
+              << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath(
+        "L:/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+      L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath(
+        "\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
+      L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
+              << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath(
+        "//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+      L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+              << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath("//") != L"//") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"//\"" << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\") != L"\\\\.\\") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"\\\\.\\\"" << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X") != L"\\\\.\\X") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"\\\\.\\X\"" << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:") != L"\\\\?\\X:") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"\\\\.\\X:\"" << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:\\") !=
+      L"\\\\?\\X:\\") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"\\\\.\\X:\\\"" << std::endl;
+    ++ret;
+  }
+
+  if (kwsys::Encoding::ToWindowsExtendedPath("NUL") != L"\\\\.\\NUL") {
+    std::cout << "Problem with ToWindowsExtendedPath "
+              << "\"NUL\"" << std::endl;
+    ++ret;
+  }
+
+  return ret;
+#else
+  return 0;
+#endif
+}
+
+//----------------------------------------------------------------------------
+int testEncoding(int, char* [])
+{
+  const char* loc = setlocale(LC_ALL, "");
+  if (loc) {
+    std::cout << "Locale: " << loc << std::endl;
+  } else {
+    std::cout << "Locale: None" << std::endl;
+  }
+
+  int ret = 0;
+
+  ret |= testHelloWorldEncoding();
+  ret |= testRobustEncoding();
+  ret |= testCommandLineArguments();
+  ret |= testWithNulls();
+  ret |= testToWindowsExtendedPath();
+
+  return ret;
+}
diff --git a/thirdparty/KWSys/adios2sys/testFStream.cxx b/thirdparty/KWSys/adios2sys/testFStream.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..670f5e7685b83faa820d231c129dce1df9fc7b68
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testFStream.cxx
@@ -0,0 +1,116 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable : 4786)
+#endif
+
+#include KWSYS_HEADER(FStream.hxx)
+#include <string.h>
+#ifdef __BORLANDC__
+#include <mem.h> /* memcmp */
+#endif
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "FStream.hxx.in"
+#endif
+
+#include <iostream>
+
+//----------------------------------------------------------------------------
+static int testNoFile()
+{
+  kwsys::ifstream in_file("NoSuchFile.txt");
+  if (in_file) {
+    return 1;
+  }
+
+  return 0;
+}
+
+static const int num_test_files = 7;
+static const int max_test_file_size = 45;
+
+static kwsys::FStream::BOM expected_bom[num_test_files] = {
+  kwsys::FStream::BOM_None,    kwsys::FStream::BOM_None,
+  kwsys::FStream::BOM_UTF8,    kwsys::FStream::BOM_UTF16LE,
+  kwsys::FStream::BOM_UTF16BE, kwsys::FStream::BOM_UTF32LE,
+  kwsys::FStream::BOM_UTF32BE
+};
+
+static unsigned char expected_bom_data[num_test_files][5] = {
+  { 0 },
+  { 0 },
+  { 3, 0xEF, 0xBB, 0xBF },
+  { 2, 0xFF, 0xFE },
+  { 2, 0xFE, 0xFF },
+  { 4, 0xFF, 0xFE, 0x00, 0x00 },
+  { 4, 0x00, 0x00, 0xFE, 0xFF },
+};
+
+static unsigned char file_data[num_test_files][max_test_file_size] = {
+  { 1, 'H' },
+  { 11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' },
+  { 11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' },
+  { 22,   0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20,
+    0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00 },
+  { 22,   0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00,
+    0x20, 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64 },
+  { 44,   0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00,
+    0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+    0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00,
+    0x00, 0x6C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00 },
+  { 44,   0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00,
+    0x6C, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00,
+    0x20, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00,
+    0x72, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64 },
+};
+
+//----------------------------------------------------------------------------
+static int testBOM()
+{
+  // test various encodings in binary mode
+  for (int i = 0; i < num_test_files; i++) {
+    {
+      kwsys::ofstream out("bom.txt", kwsys::ofstream::binary);
+      out.write(reinterpret_cast<const char*>(expected_bom_data[i] + 1),
+                *expected_bom_data[i]);
+      out.write(reinterpret_cast<const char*>(file_data[i] + 1),
+                file_data[i][0]);
+    }
+
+    kwsys::ifstream in("bom.txt", kwsys::ofstream::binary);
+    kwsys::FStream::BOM bom = kwsys::FStream::ReadBOM(in);
+    if (bom != expected_bom[i]) {
+      std::cout << "Unexpected BOM " << i << std::endl;
+      return 1;
+    }
+    char data[max_test_file_size];
+    in.read(data, file_data[i][0]);
+    if (!in.good()) {
+      std::cout << "Unable to read data " << i << std::endl;
+      return 1;
+    }
+
+    if (memcmp(data, file_data[i] + 1, file_data[i][0]) != 0) {
+      std::cout << "Incorrect read data " << i << std::endl;
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+//----------------------------------------------------------------------------
+int testFStream(int, char* [])
+{
+  int ret = 0;
+
+  ret |= testNoFile();
+  ret |= testBOM();
+
+  return ret;
+}
diff --git a/thirdparty/KWSys/adios2sys/testFail.c b/thirdparty/KWSys/adios2sys/testFail.c
new file mode 100644
index 0000000000000000000000000000000000000000..82caeac37f4f8fe0a5a50743eab109fc8c69e06b
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testFail.c
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int testFail(int argc, char* argv[])
+{
+  char* env = getenv("DASHBOARD_TEST_FROM_CTEST");
+  int oldCtest = 0;
+  if (env) {
+    if (strcmp(env, "1") == 0) {
+      oldCtest = 1;
+    }
+    printf("DASHBOARD_TEST_FROM_CTEST = %s\n", env);
+  }
+  printf("%s: This test intentionally fails\n", argv[0]);
+  if (oldCtest) {
+    printf("The version of ctest is not able to handle intentionally failing "
+           "tests, so pass.\n");
+    return 0;
+  }
+  return argc;
+}
diff --git a/thirdparty/KWSys/adios2sys/testHashSTL.cxx b/thirdparty/KWSys/adios2sys/testHashSTL.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..044487473295966f0605e4e9e734d18bb2575b34
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testHashSTL.cxx
@@ -0,0 +1,63 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(hash_map.hxx)
+#include KWSYS_HEADER(hash_set.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "hash_map.hxx.in"
+#include "hash_set.hxx.in"
+#endif
+
+#include <iostream>
+
+#if defined(_MSC_VER)
+#pragma warning(disable : 4786)
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__)
+#pragma set woff 1468 /* inline function cannot be explicitly instantiated */
+#endif
+
+template class kwsys::hash_map<const char*, int>;
+template class kwsys::hash_set<int>;
+
+static bool test_hash_map()
+{
+  typedef kwsys::hash_map<const char*, int> mtype;
+  mtype m;
+  const char* keys[] = { "hello", "world" };
+  m[keys[0]] = 1;
+  m.insert(mtype::value_type(keys[1], 2));
+  int sum = 0;
+  for (mtype::iterator mi = m.begin(); mi != m.end(); ++mi) {
+    std::cout << "Found entry [" << mi->first << "," << mi->second << "]"
+              << std::endl;
+    sum += mi->second;
+  }
+  return sum == 3;
+}
+
+static bool test_hash_set()
+{
+  typedef kwsys::hash_set<int> stype;
+  stype s;
+  s.insert(1);
+  s.insert(2);
+  int sum = 0;
+  for (stype::iterator si = s.begin(); si != s.end(); ++si) {
+    std::cout << "Found entry [" << *si << "]" << std::endl;
+    sum += *si;
+  }
+  return sum == 3;
+}
+
+int testHashSTL(int, char* [])
+{
+  bool result = true;
+  result = test_hash_map() && result;
+  result = test_hash_set() && result;
+  return result ? 0 : 1;
+}
diff --git a/thirdparty/KWSys/adios2sys/testIOS.cxx b/thirdparty/KWSys/adios2sys/testIOS.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3e4c325c767326a627e656d25519e7698dda0baf
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testIOS.cxx
@@ -0,0 +1,139 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Configure.hxx)
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string.h> /* strlen */
+#include <vector>
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "Configure.hxx.in"
+#endif
+
+int testIOS(int, char* [])
+{
+  std::ostringstream ostr;
+  const char hello[] = "hello";
+  ostr << hello;
+  if (ostr.str() != hello) {
+    std::cerr << "failed to write hello to ostr" << std::endl;
+    return 1;
+  }
+  const char world[] = "world";
+  std::ostringstream ostr2;
+  ostr2.write(hello, strlen(hello)); /* I could do sizeof */
+  ostr2.put('\0');
+  ostr2.write(world, strlen(world));
+  if (ostr2.str().size() != strlen(hello) + 1 + strlen(world)) {
+    std::cerr << "failed to write hello to ostr2" << std::endl;
+    return 1;
+  }
+  static const unsigned char array[] = {
+    0xff, 0x4f, 0xff, 0x51, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+    0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x01, 0xff, 0x52, 0x00,
+    0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x04, 0x04, 0x00, 0x01, 0xff,
+    0x5c, 0x00, 0x13, 0x40, 0x40, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48,
+    0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0xff, 0x64, 0x00, 0x2c,
+    0x00, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79,
+    0x20, 0x49, 0x54, 0x4b, 0x2f, 0x47, 0x44, 0x43, 0x4d, 0x2f, 0x4f, 0x70,
+    0x65, 0x6e, 0x4a, 0x50, 0x45, 0x47, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69,
+    0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0xff, 0x90, 0x00, 0x0a, 0x00, 0x00,
+    0x00, 0x00, 0x06, 0x2c, 0x00, 0x01, 0xff, 0x93, 0xcf, 0xb0, 0x18, 0x08,
+    0x7f, 0xc6, 0x99, 0xbf, 0xff, 0xc0, 0xf8, 0xc1, 0xc1, 0xf3, 0x05, 0x81,
+    0xf2, 0x83, 0x0a, 0xa5, 0xff, 0x10, 0x90, 0xbf, 0x2f, 0xff, 0x04, 0xa8,
+    0x7f, 0xc0, 0xf8, 0xc4, 0xc1, 0xf3, 0x09, 0x81, 0xf3, 0x0c, 0x19, 0x34
+  };
+  const size_t narray = sizeof(array); // 180
+  std::stringstream strstr;
+  strstr.write((char*)array, narray);
+  // strstr.seekp( narray / 2 ); // set position of put pointer in mid string
+  if (strstr.str().size() != narray) {
+    std::cerr << "failed to write array to strstr" << std::endl;
+    return 1;
+  }
+
+  std::istringstream istr(" 10 20 str ");
+  std::string s;
+  int x;
+  if (istr >> x) {
+    if (x != 10) {
+      std::cerr << "x != 10" << std::endl;
+      return 1;
+    }
+  } else {
+    std::cerr << "Failed to read 10 from istr" << std::endl;
+    return 1;
+  }
+  if (istr >> x) {
+    if (x != 20) {
+      std::cerr << "x != 20" << std::endl;
+      return 1;
+    }
+  } else {
+    std::cerr << "Failed to read 20 from istr" << std::endl;
+    return 1;
+  }
+  if (istr >> s) {
+    if (s != "str") {
+      std::cerr << "s != \"str\"" << std::endl;
+      return 1;
+    }
+  } else {
+    std::cerr << "Failed to read str from istr" << std::endl;
+    return 1;
+  }
+  if (istr >> s) {
+    std::cerr << "Able to read past end of stream" << std::endl;
+    return 1;
+  } else {
+    // Clear the failure.
+    istr.clear(istr.rdstate() & ~std::ios::eofbit);
+    istr.clear(istr.rdstate() & ~std::ios::failbit);
+  }
+  istr.str("30");
+  if (istr >> x) {
+    if (x != 30) {
+      std::cerr << "x != 30" << std::endl;
+      return 1;
+    }
+  } else {
+    std::cerr << "Failed to read 30 from istr" << std::endl;
+    return 1;
+  }
+
+  std::stringstream sstr;
+  sstr << "40 str2";
+  if (sstr >> x) {
+    if (x != 40) {
+      std::cerr << "x != 40" << std::endl;
+      return 1;
+    }
+  } else {
+    std::cerr << "Failed to read 40 from sstr" << std::endl;
+    return 1;
+  }
+  if (sstr >> s) {
+    if (s != "str2") {
+      std::cerr << "s != \"str2\"" << std::endl;
+      return 1;
+    }
+  } else {
+    std::cerr << "Failed to read str2 from sstr" << std::endl;
+    return 1;
+  }
+
+  // Just try to compile this.
+  if (x == 12345) {
+    std::ifstream fin("/does_not_exist", std::ios::in | std::ios::binary);
+  }
+
+  std::cout << "IOS tests passed" << std::endl;
+  return 0;
+}
diff --git a/thirdparty/KWSys/adios2sys/testProcess.c b/thirdparty/KWSys/adios2sys/testProcess.c
new file mode 100644
index 0000000000000000000000000000000000000000..092dd03476577db9344008551b9df8a47f98674b
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testProcess.c
@@ -0,0 +1,711 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Process.h)
+#include KWSYS_HEADER(Encoding.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "Encoding.h.in"
+#include "Process.h.in"
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_WIN32)
+#include <windows.h>
+#else
+#include <signal.h>
+#include <unistd.h>
+#endif
+
+#if defined(__BORLANDC__)
+#pragma warn - 8060 /* possibly incorrect assignment */
+#endif
+
+/* Platform-specific sleep functions. */
+
+#if defined(__BEOS__) && !defined(__ZETA__)
+/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
+#include <be/kernel/OS.h>
+static inline void testProcess_usleep(unsigned int usec)
+{
+  snooze(usec);
+}
+#elif defined(_WIN32)
+/* Windows can only sleep in millisecond intervals. */
+static void testProcess_usleep(unsigned int usec)
+{
+  Sleep(usec / 1000);
+}
+#else
+#define testProcess_usleep usleep
+#endif
+
+#if defined(_WIN32)
+static void testProcess_sleep(unsigned int sec)
+{
+  Sleep(sec * 1000);
+}
+#else
+static void testProcess_sleep(unsigned int sec)
+{
+  sleep(sec);
+}
+#endif
+
+int runChild(const char* cmd[], int state, int exception, int value, int share,
+             int output, int delay, double timeout, int poll, int repeat,
+             int disown, int createNewGroup, unsigned int interruptDelay);
+
+static int test1(int argc, const char* argv[])
+{
+  /* This is a very basic functional test of kwsysProcess.  It is repeated
+     numerous times to verify that there are no resource leaks in kwsysProcess
+     that eventually lead to an error.  Many versions of OS X will fail after
+     256 leaked file handles, so 257 iterations seems to be a good test.  On
+     the other hand, too many iterations will cause the test to time out -
+     especially if the test is instrumented with e.g. valgrind.
+
+     If you have problems with this test timing out on your system, or want to
+     run more than 257 iterations, you can change the number of iterations by
+     setting the KWSYS_TEST_PROCESS_1_COUNT environment variable.  */
+  (void)argc;
+  (void)argv;
+  fprintf(stdout, "Output on stdout from test returning 0.\n");
+  fprintf(stderr, "Output on stderr from test returning 0.\n");
+  return 0;
+}
+
+static int test2(int argc, const char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  fprintf(stdout, "Output on stdout from test returning 123.\n");
+  fprintf(stderr, "Output on stderr from test returning 123.\n");
+  return 123;
+}
+
+static int test3(int argc, const char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  fprintf(stdout, "Output before sleep on stdout from timeout test.\n");
+  fprintf(stderr, "Output before sleep on stderr from timeout test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  testProcess_sleep(15);
+  fprintf(stdout, "Output after sleep on stdout from timeout test.\n");
+  fprintf(stderr, "Output after sleep on stderr from timeout test.\n");
+  return 0;
+}
+
+static int test4(int argc, const char* argv[])
+{
+  /* Prepare a pointer to an invalid address.  Don't use null, because
+  dereferencing null is undefined behaviour and compilers are free to
+  do whatever they want. ex: Clang will warn at compile time, or even
+  optimize away the write. We hope to 'outsmart' them by using
+  'volatile' and a slightly larger address, based on a runtime value. */
+  volatile int* invalidAddress = 0;
+  invalidAddress += argc ? 1 : 2;
+
+#if defined(_WIN32)
+  /* Avoid error diagnostic popups since we are crashing on purpose.  */
+  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+#elif defined(__BEOS__) || defined(__HAIKU__)
+  /* Avoid error diagnostic popups since we are crashing on purpose.  */
+  disable_debugger(1);
+#endif
+  (void)argc;
+  (void)argv;
+  fprintf(stdout, "Output before crash on stdout from crash test.\n");
+  fprintf(stderr, "Output before crash on stderr from crash test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  assert(invalidAddress); /* Quiet Clang scan-build. */
+  /* Provoke deliberate crash by writing to the invalid address. */
+  *invalidAddress = 0;
+  fprintf(stdout, "Output after crash on stdout from crash test.\n");
+  fprintf(stderr, "Output after crash on stderr from crash test.\n");
+  return 0;
+}
+
+static int test5(int argc, const char* argv[])
+{
+  int r;
+  const char* cmd[4];
+  (void)argc;
+  cmd[0] = argv[0];
+  cmd[1] = "run";
+  cmd[2] = "4";
+  cmd[3] = 0;
+  fprintf(stdout, "Output on stdout before recursive test.\n");
+  fprintf(stderr, "Output on stderr before recursive test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  r = runChild(cmd, kwsysProcess_State_Exception, kwsysProcess_Exception_Fault,
+               1, 1, 1, 0, 15, 0, 1, 0, 0, 0);
+  fprintf(stdout, "Output on stdout after recursive test.\n");
+  fprintf(stderr, "Output on stderr after recursive test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  return r;
+}
+
+#define TEST6_SIZE (4096 * 2)
+static void test6(int argc, const char* argv[])
+{
+  int i;
+  char runaway[TEST6_SIZE + 1];
+  (void)argc;
+  (void)argv;
+  for (i = 0; i < TEST6_SIZE; ++i) {
+    runaway[i] = '.';
+  }
+  runaway[TEST6_SIZE] = '\n';
+
+  /* Generate huge amounts of output to test killing.  */
+  for (;;) {
+    fwrite(runaway, 1, TEST6_SIZE + 1, stdout);
+    fflush(stdout);
+  }
+}
+
+/* Define MINPOLL to be one more than the number of times output is
+   written.  Define MAXPOLL to be the largest number of times a loop
+   delaying 1/10th of a second should ever have to poll.  */
+#define MINPOLL 5
+#define MAXPOLL 20
+static int test7(int argc, const char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  fprintf(stdout, "Output on stdout before sleep.\n");
+  fprintf(stderr, "Output on stderr before sleep.\n");
+  fflush(stdout);
+  fflush(stderr);
+  /* Sleep for 1 second.  */
+  testProcess_sleep(1);
+  fprintf(stdout, "Output on stdout after sleep.\n");
+  fprintf(stderr, "Output on stderr after sleep.\n");
+  fflush(stdout);
+  fflush(stderr);
+  return 0;
+}
+
+static int test8(int argc, const char* argv[])
+{
+  /* Create a disowned grandchild to test handling of processes
+     that exit before their children.  */
+  int r;
+  const char* cmd[4];
+  (void)argc;
+  cmd[0] = argv[0];
+  cmd[1] = "run";
+  cmd[2] = "108";
+  cmd[3] = 0;
+  fprintf(stdout, "Output on stdout before grandchild test.\n");
+  fprintf(stderr, "Output on stderr before grandchild test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None,
+               1, 1, 1, 0, 10, 0, 1, 1, 0, 0);
+  fprintf(stdout, "Output on stdout after grandchild test.\n");
+  fprintf(stderr, "Output on stderr after grandchild test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  return r;
+}
+
+static int test8_grandchild(int argc, const char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+  fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+  fflush(stdout);
+  fflush(stderr);
+  /* TODO: Instead of closing pipes here leave them open to make sure
+     the grandparent can stop listening when the parent exits.  This
+     part of the test cannot be enabled until the feature is
+     implemented.  */
+  fclose(stdout);
+  fclose(stderr);
+  testProcess_sleep(15);
+  return 0;
+}
+
+static int test9(int argc, const char* argv[])
+{
+  /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this
+     process.  Here, we start a child process that sleeps for a long time
+     while ignoring signals.  The test is successful if this process waits
+     for the child to return before exiting from the Ctrl+C handler.
+
+     WARNING:  This test will falsely pass if the share parameter of runChild
+     was set to 0 when invoking the test9 process.  */
+  int r;
+  const char* cmd[4];
+  (void)argc;
+  cmd[0] = argv[0];
+  cmd[1] = "run";
+  cmd[2] = "109";
+  cmd[3] = 0;
+  fprintf(stdout, "Output on stdout before grandchild test.\n");
+  fprintf(stderr, "Output on stderr before grandchild test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  r = runChild(cmd, kwsysProcess_State_Exited, kwsysProcess_Exception_None, 0,
+               1, 1, 0, 30, 0, 1, 0, 0, 0);
+  /* This sleep will avoid a race condition between this function exiting
+     normally and our Ctrl+C handler exiting abnormally after the process
+     exits.  */
+  testProcess_sleep(1);
+  fprintf(stdout, "Output on stdout after grandchild test.\n");
+  fprintf(stderr, "Output on stderr after grandchild test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  return r;
+}
+
+#if defined(_WIN32)
+static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType)
+{
+  /* Ignore all Ctrl+C/Break signals.  We must use an actual handler function
+     instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also
+     ignore Ctrl+Break in addition to Ctrl+C.  */
+  (void)dwCtrlType;
+  return TRUE;
+}
+#endif
+
+static int test9_grandchild(int argc, const char* argv[])
+{
+  /* The grandchild just sleeps for a few seconds while ignoring signals.  */
+  (void)argc;
+  (void)argv;
+#if defined(_WIN32)
+  if (!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE)) {
+    return 1;
+  }
+#else
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = SIG_IGN;
+  sigemptyset(&sa.sa_mask);
+  if (sigaction(SIGINT, &sa, 0) < 0) {
+    return 1;
+  }
+#endif
+  fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+  fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+  fflush(stdout);
+  fflush(stderr);
+  /* Sleep for 9 seconds.  */
+  testProcess_sleep(9);
+  fprintf(stdout, "Output on stdout from grandchild after sleep.\n");
+  fprintf(stderr, "Output on stderr from grandchild after sleep.\n");
+  fflush(stdout);
+  fflush(stderr);
+  return 0;
+}
+
+static int test10(int argc, const char* argv[])
+{
+  /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this
+     process.  Here, we start a child process that sleeps for a long time and
+     processes signals normally.  However, this grandchild is created in a new
+     process group - ensuring that Ctrl+C we receive is sent to our process
+     groups.  We make sure it exits anyway.  */
+  int r;
+  const char* cmd[4];
+  (void)argc;
+  cmd[0] = argv[0];
+  cmd[1] = "run";
+  cmd[2] = "110";
+  cmd[3] = 0;
+  fprintf(stdout, "Output on stdout before grandchild test.\n");
+  fprintf(stderr, "Output on stderr before grandchild test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  r =
+    runChild(cmd, kwsysProcess_State_Exception,
+             kwsysProcess_Exception_Interrupt, 0, 1, 1, 0, 30, 0, 1, 0, 1, 0);
+  fprintf(stdout, "Output on stdout after grandchild test.\n");
+  fprintf(stderr, "Output on stderr after grandchild test.\n");
+  fflush(stdout);
+  fflush(stderr);
+  return r;
+}
+
+static int test10_grandchild(int argc, const char* argv[])
+{
+  /* The grandchild just sleeps for a few seconds and handles signals.  */
+  (void)argc;
+  (void)argv;
+  fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+  fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+  fflush(stdout);
+  fflush(stderr);
+  /* Sleep for 6 seconds.  */
+  testProcess_sleep(6);
+  fprintf(stdout, "Output on stdout from grandchild after sleep.\n");
+  fprintf(stderr, "Output on stderr from grandchild after sleep.\n");
+  fflush(stdout);
+  fflush(stderr);
+  return 0;
+}
+
+static int runChild2(kwsysProcess* kp, const char* cmd[], int state,
+                     int exception, int value, int share, int output,
+                     int delay, double timeout, int poll, int disown,
+                     int createNewGroup, unsigned int interruptDelay)
+{
+  int result = 0;
+  char* data = 0;
+  int length = 0;
+  double userTimeout = 0;
+  double* pUserTimeout = 0;
+  kwsysProcess_SetCommand(kp, cmd);
+  if (timeout >= 0) {
+    kwsysProcess_SetTimeout(kp, timeout);
+  }
+  if (share) {
+    kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1);
+    kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1);
+  }
+  if (disown) {
+    kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1);
+  }
+  if (createNewGroup) {
+    kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1);
+  }
+  kwsysProcess_Execute(kp);
+
+  if (poll) {
+    pUserTimeout = &userTimeout;
+  }
+
+  if (interruptDelay) {
+    testProcess_sleep(interruptDelay);
+    kwsysProcess_Interrupt(kp);
+  }
+
+  if (!share && !disown) {
+    int p;
+    while ((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout))) {
+      if (output) {
+        if (poll && p == kwsysProcess_Pipe_Timeout) {
+          fprintf(stdout, "WaitForData timeout reached.\n");
+          fflush(stdout);
+
+          /* Count the number of times we polled without getting data.
+             If it is excessive then kill the child and fail.  */
+          if (++poll >= MAXPOLL) {
+            fprintf(stdout, "Poll count reached limit %d.\n", MAXPOLL);
+            kwsysProcess_Kill(kp);
+          }
+        } else {
+          fwrite(data, 1, (size_t)length, stdout);
+          fflush(stdout);
+        }
+      }
+      if (poll) {
+        /* Delay to avoid busy loop during polling.  */
+        testProcess_usleep(100000);
+      }
+      if (delay) {
+/* Purposely sleeping only on Win32 to let pipe fill up.  */
+#if defined(_WIN32)
+        testProcess_usleep(100000);
+#endif
+      }
+    }
+  }
+
+  if (disown) {
+    kwsysProcess_Disown(kp);
+  } else {
+    kwsysProcess_WaitForExit(kp, 0);
+  }
+
+  switch (kwsysProcess_GetState(kp)) {
+    case kwsysProcess_State_Starting:
+      printf("No process has been executed.\n");
+      break;
+    case kwsysProcess_State_Executing:
+      printf("The process is still executing.\n");
+      break;
+    case kwsysProcess_State_Expired:
+      printf("Child was killed when timeout expired.\n");
+      break;
+    case kwsysProcess_State_Exited:
+      printf("Child exited with value = %d\n", kwsysProcess_GetExitValue(kp));
+      result = ((exception != kwsysProcess_GetExitException(kp)) ||
+                (value != kwsysProcess_GetExitValue(kp)));
+      break;
+    case kwsysProcess_State_Killed:
+      printf("Child was killed by parent.\n");
+      break;
+    case kwsysProcess_State_Exception:
+      printf("Child terminated abnormally: %s\n",
+             kwsysProcess_GetExceptionString(kp));
+      result = ((exception != kwsysProcess_GetExitException(kp)) ||
+                (value != kwsysProcess_GetExitValue(kp)));
+      break;
+    case kwsysProcess_State_Disowned:
+      printf("Child was disowned.\n");
+      break;
+    case kwsysProcess_State_Error:
+      printf("Error in administrating child process: [%s]\n",
+             kwsysProcess_GetErrorString(kp));
+      break;
+  };
+
+  if (result) {
+    if (exception != kwsysProcess_GetExitException(kp)) {
+      fprintf(stderr, "Mismatch in exit exception.  "
+                      "Should have been %d, was %d.\n",
+              exception, kwsysProcess_GetExitException(kp));
+    }
+    if (value != kwsysProcess_GetExitValue(kp)) {
+      fprintf(stderr, "Mismatch in exit value.  "
+                      "Should have been %d, was %d.\n",
+              value, kwsysProcess_GetExitValue(kp));
+    }
+  }
+
+  if (kwsysProcess_GetState(kp) != state) {
+    fprintf(stderr, "Mismatch in state.  "
+                    "Should have been %d, was %d.\n",
+            state, kwsysProcess_GetState(kp));
+    result = 1;
+  }
+
+  /* We should have polled more times than there were data if polling
+     was enabled.  */
+  if (poll && poll < MINPOLL) {
+    fprintf(stderr, "Poll count is %d, which is less than %d.\n", poll,
+            MINPOLL);
+    result = 1;
+  }
+
+  return result;
+}
+
+/**
+ * Runs a child process and blocks until it returns.  Arguments as follows:
+ *
+ * cmd            = Command line to run.
+ * state          = Expected return value of kwsysProcess_GetState after exit.
+ * exception      = Expected return value of kwsysProcess_GetExitException.
+ * value          = Expected return value of kwsysProcess_GetExitValue.
+ * share          = Whether to share stdout/stderr child pipes with our pipes
+ *                  by way of kwsysProcess_SetPipeShared.  If false, new pipes
+ *                  are created.
+ * output         = If !share && !disown, whether to write the child's stdout
+ *                  and stderr output to our stdout.
+ * delay          = If !share && !disown, adds an additional short delay to
+ *                  the pipe loop to allow the pipes to fill up; Windows only.
+ * timeout        = Non-zero to sets a timeout in seconds via
+ *                  kwsysProcess_SetTimeout.
+ * poll           = If !share && !disown, we count the number of 0.1 second
+ *                  intervals where the child pipes had no new data.  We fail
+ *                  if not in the bounds of MINPOLL/MAXPOLL.
+ * repeat         = Number of times to run the process.
+ * disown         = If set, the process is disowned.
+ * createNewGroup = If set, the process is created in a new process group.
+ * interruptDelay = If non-zero, number of seconds to delay before
+ *                  interrupting the process.  Note that this delay will occur
+ *                  BEFORE any reading/polling of pipes occurs and before any
+ *                  detachment occurs.
+ */
+int runChild(const char* cmd[], int state, int exception, int value, int share,
+             int output, int delay, double timeout, int poll, int repeat,
+             int disown, int createNewGroup, unsigned int interruptDelay)
+{
+  int result = 1;
+  kwsysProcess* kp = kwsysProcess_New();
+  if (!kp) {
+    fprintf(stderr, "kwsysProcess_New returned NULL!\n");
+    return 1;
+  }
+  while (repeat-- > 0) {
+    result = runChild2(kp, cmd, state, exception, value, share, output, delay,
+                       timeout, poll, disown, createNewGroup, interruptDelay);
+    if (result) {
+      break;
+    }
+  }
+  kwsysProcess_Delete(kp);
+  return result;
+}
+
+int main(int argc, const char* argv[])
+{
+  int n = 0;
+
+#ifdef _WIN32
+  int i;
+  char new_args[10][_MAX_PATH];
+  LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &argc);
+  for (i = 0; i < argc; i++) {
+    kwsysEncoding_wcstombs(new_args[i], w_av[i], _MAX_PATH);
+    argv[i] = new_args[i];
+  }
+  LocalFree(w_av);
+#endif
+
+#if 0
+    {
+    HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
+    DuplicateHandle(GetCurrentProcess(), out,
+                    GetCurrentProcess(), &out, 0, FALSE,
+                    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+    SetStdHandle(STD_OUTPUT_HANDLE, out);
+    }
+    {
+    HANDLE out = GetStdHandle(STD_ERROR_HANDLE);
+    DuplicateHandle(GetCurrentProcess(), out,
+                    GetCurrentProcess(), &out, 0, FALSE,
+                    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+    SetStdHandle(STD_ERROR_HANDLE, out);
+    }
+#endif
+  if (argc == 2) {
+    n = atoi(argv[1]);
+  } else if (argc == 3 && strcmp(argv[1], "run") == 0) {
+    n = atoi(argv[2]);
+  }
+  /* Check arguments.  */
+  if (((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3) {
+    /* This is the child process for a requested test number.  */
+    switch (n) {
+      case 1:
+        return test1(argc, argv);
+      case 2:
+        return test2(argc, argv);
+      case 3:
+        return test3(argc, argv);
+      case 4:
+        return test4(argc, argv);
+      case 5:
+        return test5(argc, argv);
+      case 6:
+        test6(argc, argv);
+        return 0;
+      case 7:
+        return test7(argc, argv);
+      case 8:
+        return test8(argc, argv);
+      case 9:
+        return test9(argc, argv);
+      case 10:
+        return test10(argc, argv);
+      case 108:
+        return test8_grandchild(argc, argv);
+      case 109:
+        return test9_grandchild(argc, argv);
+      case 110:
+        return test10_grandchild(argc, argv);
+    }
+    fprintf(stderr, "Invalid test number %d.\n", n);
+    return 1;
+  } else if (n >= 1 && n <= 10) {
+    /* This is the parent process for a requested test number.  */
+    int states[10] = {
+      kwsysProcess_State_Exited,   kwsysProcess_State_Exited,
+      kwsysProcess_State_Expired,  kwsysProcess_State_Exception,
+      kwsysProcess_State_Exited,   kwsysProcess_State_Expired,
+      kwsysProcess_State_Exited,   kwsysProcess_State_Exited,
+      kwsysProcess_State_Expired,  /* Ctrl+C handler test */
+      kwsysProcess_State_Exception /* Process group test */
+    };
+    int exceptions[10] = {
+      kwsysProcess_Exception_None, kwsysProcess_Exception_None,
+      kwsysProcess_Exception_None, kwsysProcess_Exception_Fault,
+      kwsysProcess_Exception_None, kwsysProcess_Exception_None,
+      kwsysProcess_Exception_None, kwsysProcess_Exception_None,
+      kwsysProcess_Exception_None, kwsysProcess_Exception_Interrupt
+    };
+    int values[10] = { 0, 123, 1, 1, 0, 0, 0, 0, 1, 1 };
+    int shares[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+    int outputs[10] = { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 };
+    int delays[10] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 };
+    double timeouts[10] = { 10, 10, 10, 30, 30, 10, -1, 10, 6, 4 };
+    int polls[10] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
+    int repeat[10] = { 257, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+    int createNewGroups[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+    unsigned int interruptDelays[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 2 };
+    int r;
+    const char* cmd[4];
+#ifdef _WIN32
+    char* argv0 = 0;
+#endif
+    char* test1IterationsStr = getenv("KWSYS_TEST_PROCESS_1_COUNT");
+    if (test1IterationsStr) {
+      long int test1Iterations = strtol(test1IterationsStr, 0, 10);
+      if (test1Iterations > 10 && test1Iterations != LONG_MAX) {
+        repeat[0] = (int)test1Iterations;
+      }
+    }
+#ifdef _WIN32
+    if (n == 0 && (argv0 = strdup(argv[0]))) {
+      /* Try converting to forward slashes to see if it works.  */
+      char* c;
+      for (c = argv0; *c; ++c) {
+        if (*c == '\\') {
+          *c = '/';
+        }
+      }
+      cmd[0] = argv0;
+    } else {
+      cmd[0] = argv[0];
+    }
+#else
+    cmd[0] = argv[0];
+#endif
+    cmd[1] = "run";
+    cmd[2] = argv[1];
+    cmd[3] = 0;
+    fprintf(stdout, "Output on stdout before test %d.\n", n);
+    fprintf(stderr, "Output on stderr before test %d.\n", n);
+    fflush(stdout);
+    fflush(stderr);
+    r = runChild(cmd, states[n - 1], exceptions[n - 1], values[n - 1],
+                 shares[n - 1], outputs[n - 1], delays[n - 1], timeouts[n - 1],
+                 polls[n - 1], repeat[n - 1], 0, createNewGroups[n - 1],
+                 interruptDelays[n - 1]);
+    fprintf(stdout, "Output on stdout after test %d.\n", n);
+    fprintf(stderr, "Output on stderr after test %d.\n", n);
+    fflush(stdout);
+    fflush(stderr);
+#if defined(_WIN32)
+    if (argv0) {
+      free(argv0);
+    }
+#endif
+    return r;
+  } else if (argc > 2 && strcmp(argv[1], "0") == 0) {
+    /* This is the special debugging test to run a given command
+       line.  */
+    const char** cmd = argv + 2;
+    int state = kwsysProcess_State_Exited;
+    int exception = kwsysProcess_Exception_None;
+    int value = 0;
+    double timeout = 0;
+    int r =
+      runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0, 0, 0);
+    return r;
+  } else {
+    /* Improper usage.  */
+    fprintf(stdout, "Usage: %s <test number>\n", argv[0]);
+    return 1;
+  }
+}
diff --git a/thirdparty/KWSys/adios2sys/testSharedForward.c.in b/thirdparty/KWSys/adios2sys/testSharedForward.c.in
new file mode 100644
index 0000000000000000000000000000000000000000..9a0c0c0614a6d88f08db8ed34a9d6e13b9237796
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testSharedForward.c.in
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#if defined(CMAKE_INTDIR)
+#define CONFIG_DIR_PRE CMAKE_INTDIR "/"
+#define CONFIG_DIR_POST "/" CMAKE_INTDIR
+#else
+#define CONFIG_DIR_PRE ""
+#define CONFIG_DIR_POST ""
+#endif
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "@EXEC_DIR@"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL 0
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD                            \
+  CONFIG_DIR_PRE "@KWSYS_NAMESPACE@TestProcess"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL                          \
+  "@KWSYS_NAMESPACE@TestProcess"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print"
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd"
+#if defined(CMAKE_INTDIR)
+#define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR
+#endif
+#include <@KWSYS_NAMESPACE@/SharedForward.h>
+int main(int argc, char** argv)
+{
+  return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv);
+}
diff --git a/thirdparty/KWSys/adios2sys/testSystemInformation.cxx b/thirdparty/KWSys/adios2sys/testSystemInformation.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3a9217f2c769daf103f31cdc9aeb1285f0bb78d7
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testSystemInformation.cxx
@@ -0,0 +1,106 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(SystemInformation.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "SystemInformation.hxx.in"
+#endif
+
+#include <iostream>
+
+#if defined(KWSYS_USE_LONG_LONG)
+#if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
+#define iostreamLongLong(x) (x)
+#else
+#define iostreamLongLong(x) ((long)x)
+#endif
+#elif defined(KWSYS_USE___INT64)
+#if defined(KWSYS_IOS_HAS_OSTREAM___INT64)
+#define iostreamLongLong(x) (x)
+#else
+#define iostreamLongLong(x) ((long)x)
+#endif
+#else
+#error "No Long Long"
+#endif
+
+#define printMethod(info, m) std::cout << #m << ": " << info.m() << "\n"
+
+#define printMethod2(info, m, unit)                                           \
+  std::cout << #m << ": " << info.m() << " " << unit << "\n"
+
+#define printMethod3(info, m, unit)                                           \
+  std::cout << #m << ": " << iostreamLongLong(info.m) << " " << unit << "\n"
+
+int testSystemInformation(int, char* [])
+{
+  std::cout << "CTEST_FULL_OUTPUT\n"; // avoid truncation
+
+  kwsys::SystemInformation info;
+  info.RunCPUCheck();
+  info.RunOSCheck();
+  info.RunMemoryCheck();
+  printMethod(info, GetOSName);
+  printMethod(info, GetOSIsLinux);
+  printMethod(info, GetOSIsApple);
+  printMethod(info, GetOSIsWindows);
+  printMethod(info, GetHostname);
+  printMethod(info, GetFullyQualifiedDomainName);
+  printMethod(info, GetOSRelease);
+  printMethod(info, GetOSVersion);
+  printMethod(info, GetOSPlatform);
+  printMethod(info, Is64Bits);
+  printMethod(info, GetVendorString);
+  printMethod(info, GetVendorID);
+  printMethod(info, GetTypeID);
+  printMethod(info, GetFamilyID);
+  printMethod(info, GetModelID);
+  printMethod(info, GetExtendedProcessorName);
+  printMethod(info, GetSteppingCode);
+  printMethod(info, GetProcessorSerialNumber);
+  printMethod2(info, GetProcessorCacheSize, "KB");
+  printMethod(info, GetLogicalProcessorsPerPhysical);
+  printMethod2(info, GetProcessorClockFrequency, "MHz");
+  printMethod(info, GetNumberOfLogicalCPU);
+  printMethod(info, GetNumberOfPhysicalCPU);
+  printMethod(info, DoesCPUSupportCPUID);
+  printMethod(info, GetProcessorAPICID);
+  printMethod2(info, GetTotalVirtualMemory, "MB");
+  printMethod2(info, GetAvailableVirtualMemory, "MB");
+  printMethod2(info, GetTotalPhysicalMemory, "MB");
+  printMethod2(info, GetAvailablePhysicalMemory, "MB");
+  printMethod3(info, GetHostMemoryTotal(), "KiB");
+  printMethod3(info, GetHostMemoryAvailable("KWSHL"), "KiB");
+  printMethod3(info, GetProcMemoryAvailable("KWSHL", "KWSPL"), "KiB");
+  printMethod3(info, GetHostMemoryUsed(), "KiB");
+  printMethod3(info, GetProcMemoryUsed(), "KiB");
+  printMethod(info, GetLoadAverage);
+
+  for (long int i = 0; i <= 31; i++) {
+    if (info.DoesCPUSupportFeature(static_cast<long int>(1) << i)) {
+      std::cout << "CPU feature " << i << "\n";
+    }
+  }
+
+  /* test stack trace
+  */
+  std::cout << "Program Stack:" << std::endl
+            << kwsys::SystemInformation::GetProgramStack(0, 0) << std::endl
+            << std::endl;
+
+  /* test segv handler
+  info.SetStackTraceOnError(1);
+  double *d = (double*)100;
+  *d=0;
+  */
+
+  /* test abort handler
+  info.SetStackTraceOnError(1);
+  abort();
+  */
+
+  return 0;
+}
diff --git a/thirdparty/KWSys/adios2sys/testSystemTools.bin b/thirdparty/KWSys/adios2sys/testSystemTools.bin
new file mode 100644
index 0000000000000000000000000000000000000000..961a4043b9b2785351ab26a33cfcb1f366c1391b
Binary files /dev/null and b/thirdparty/KWSys/adios2sys/testSystemTools.bin differ
diff --git a/thirdparty/KWSys/adios2sys/testSystemTools.cxx b/thirdparty/KWSys/adios2sys/testSystemTools.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d11bcaef87563d92f8b4f98ecdfa7249d0eaff49
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testSystemTools.cxx
@@ -0,0 +1,884 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable : 4786)
+#endif
+
+#include KWSYS_HEADER(FStream.hxx)
+#include KWSYS_HEADER(SystemTools.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#include "FStream.hxx.in"
+#include "SystemTools.hxx.in"
+#endif
+
+// Include with <> instead of "" to avoid getting any in-source copy
+// left on disk.
+#include <testSystemTools.h>
+
+#include <iostream>
+#include <sstream>
+#include <string.h> /* strcmp */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <io.h> /* _umask (MSVC) / umask (Borland) */
+#ifdef _MSC_VER
+#define umask _umask // Note this is still umask on Borland
+#endif
+#endif
+#include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */
+// Visual C++ does not define mode_t (note that Borland does, however).
+#if defined(_MSC_VER)
+typedef unsigned short mode_t;
+#endif
+
+//----------------------------------------------------------------------------
+static const char* toUnixPaths[][2] = {
+  { "/usr/local/bin/passwd", "/usr/local/bin/passwd" },
+  { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" },
+  { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" },
+  { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" },
+  { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" },
+  { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" },
+  { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" },
+  { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" },
+  { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" },
+  { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" },
+  { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" },
+  { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" },
+  { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" },
+  { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" },
+  { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo\\ cal/bin/pa\\ sswd" },
+  { 0, 0 }
+};
+
+static bool CheckConvertToUnixSlashes(std::string input, std::string output)
+{
+  std::string result = input;
+  kwsys::SystemTools::ConvertToUnixSlashes(result);
+  if (result != output) {
+    std::cerr << "Problem with ConvertToUnixSlashes - input: " << input
+              << " output: " << result << " expected: " << output << std::endl;
+    return false;
+  }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+static const char* checkEscapeChars[][4] = { { "1 foo 2 bar 2", "12", "\\",
+                                               "\\1 foo \\2 bar \\2" },
+                                             { " {} ", "{}", "#", " #{#} " },
+                                             { 0, 0, 0, 0 } };
+
+static bool CheckEscapeChars(std::string input, const char* chars_to_escape,
+                             char escape_char, std::string output)
+{
+  std::string result = kwsys::SystemTools::EscapeChars(
+    input.c_str(), chars_to_escape, escape_char);
+  if (result != output) {
+    std::cerr << "Problem with CheckEscapeChars - input: " << input
+              << " output: " << result << " expected: " << output << std::endl;
+    return false;
+  }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+static bool CheckFileOperations()
+{
+  bool res = true;
+  const std::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+                                        "/testSystemToolsNonExistingFile");
+  const std::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR "/.");
+  const std::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+                                "/testSystemTools.bin");
+  const std::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+                                "/testSystemTools.cxx");
+  const std::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR
+                               "/testSystemToolsNewDir");
+  const std::string testNewFile(testNewDir + "/testNewFile.txt");
+
+  if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) !=
+      kwsys::SystemTools::FileTypeUnknown) {
+    std::cerr << "Problem with DetectFileType - failed to detect type of: "
+              << testNonExistingFile << std::endl;
+    res = false;
+  }
+
+  if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) !=
+      kwsys::SystemTools::FileTypeUnknown) {
+    std::cerr << "Problem with DetectFileType - failed to detect type of: "
+              << testDotFile << std::endl;
+    res = false;
+  }
+
+  if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) !=
+      kwsys::SystemTools::FileTypeBinary) {
+    std::cerr << "Problem with DetectFileType - failed to detect type of: "
+              << testBinFile << std::endl;
+    res = false;
+  }
+
+  if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) !=
+      kwsys::SystemTools::FileTypeText) {
+    std::cerr << "Problem with DetectFileType - failed to detect type of: "
+              << testTxtFile << std::endl;
+    res = false;
+  }
+
+  if (kwsys::SystemTools::FileLength(testBinFile) != 766) {
+    std::cerr << "Problem with FileLength - incorrect length for: "
+              << testBinFile << std::endl;
+    res = false;
+  }
+
+  kwsys::SystemTools::Stat_t buf;
+  if (kwsys::SystemTools::Stat(testTxtFile.c_str(), &buf) != 0) {
+    std::cerr << "Problem with Stat - unable to stat text file: "
+              << testTxtFile << std::endl;
+    res = false;
+  }
+
+  if (kwsys::SystemTools::Stat(testBinFile, &buf) != 0) {
+    std::cerr << "Problem with Stat - unable to stat bin file: " << testBinFile
+              << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::MakeDirectory(testNewDir)) {
+    std::cerr << "Problem with MakeDirectory for: " << testNewDir << std::endl;
+    res = false;
+  }
+  // calling it again should just return true
+  if (!kwsys::SystemTools::MakeDirectory(testNewDir)) {
+    std::cerr << "Problem with second call to MakeDirectory for: "
+              << testNewDir << std::endl;
+    res = false;
+  }
+  // calling with 0 pointer should return false
+  if (kwsys::SystemTools::MakeDirectory(0)) {
+    std::cerr << "Problem with MakeDirectory(0)" << std::endl;
+    res = false;
+  }
+  // calling with an empty string should return false
+  if (kwsys::SystemTools::MakeDirectory(std::string())) {
+    std::cerr << "Problem with MakeDirectory(std::string())" << std::endl;
+    res = false;
+  }
+  // check existence
+  if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
+    std::cerr << "Problem with FileExists as C string and not file for: "
+              << testNewDir << std::endl;
+    res = false;
+  }
+  // check existence
+  if (!kwsys::SystemTools::PathExists(testNewDir)) {
+    std::cerr << "Problem with PathExists for: " << testNewDir << std::endl;
+    res = false;
+  }
+  // remove it
+  if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) {
+    std::cerr << "Problem with RemoveADirectory for: " << testNewDir
+              << std::endl;
+    res = false;
+  }
+  // check existence
+  if (kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
+    std::cerr << "After RemoveADirectory: "
+              << "Problem with FileExists as C string and not file for: "
+              << testNewDir << std::endl;
+    res = false;
+  }
+  // check existence
+  if (kwsys::SystemTools::PathExists(testNewDir)) {
+    std::cerr << "After RemoveADirectory: "
+              << "Problem with PathExists for: " << testNewDir << std::endl;
+    res = false;
+  }
+  // create it using the char* version
+  if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str())) {
+    std::cerr << "Problem with second call to MakeDirectory as C string for: "
+              << testNewDir << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::Touch(testNewFile.c_str(), true)) {
+    std::cerr << "Problem with Touch for: " << testNewFile << std::endl;
+    res = false;
+  }
+  // calling MakeDirectory with something that is no file should fail
+  if (kwsys::SystemTools::MakeDirectory(testNewFile)) {
+    std::cerr << "Problem with to MakeDirectory for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  // calling with 0 pointer should return false
+  if (kwsys::SystemTools::FileExists(0)) {
+    std::cerr << "Problem with FileExists(0)" << std::endl;
+    res = false;
+  }
+  if (kwsys::SystemTools::FileExists(0, true)) {
+    std::cerr << "Problem with FileExists(0) as file" << std::endl;
+    res = false;
+  }
+  // calling with an empty string should return false
+  if (kwsys::SystemTools::FileExists(std::string())) {
+    std::cerr << "Problem with FileExists(std::string())" << std::endl;
+    res = false;
+  }
+  // FileExists(x, true) should return false on a directory
+  if (kwsys::SystemTools::FileExists(testNewDir, true)) {
+    std::cerr << "Problem with FileExists as file for: " << testNewDir
+              << std::endl;
+    res = false;
+  }
+  if (kwsys::SystemTools::FileExists(testNewDir.c_str(), true)) {
+    std::cerr << "Problem with FileExists as C string and file for: "
+              << testNewDir << std::endl;
+    res = false;
+  }
+  // FileExists(x, false) should return true even on a directory
+  if (!kwsys::SystemTools::FileExists(testNewDir, false)) {
+    std::cerr << "Problem with FileExists as not file for: " << testNewDir
+              << std::endl;
+    res = false;
+  }
+  if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
+    std::cerr << "Problem with FileExists as C string and not file for: "
+              << testNewDir << std::endl;
+    res = false;
+  }
+  // should work, was created as new file before
+  if (!kwsys::SystemTools::FileExists(testNewFile)) {
+    std::cerr << "Problem with FileExists for: " << testNewDir << std::endl;
+    res = false;
+  }
+  if (!kwsys::SystemTools::FileExists(testNewFile.c_str())) {
+    std::cerr << "Problem with FileExists as C string for: " << testNewDir
+              << std::endl;
+    res = false;
+  }
+  if (!kwsys::SystemTools::FileExists(testNewFile, true)) {
+    std::cerr << "Problem with FileExists as file for: " << testNewDir
+              << std::endl;
+    res = false;
+  }
+  if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true)) {
+    std::cerr << "Problem with FileExists as C string and file for: "
+              << testNewDir << std::endl;
+    res = false;
+  }
+
+  // calling with an empty string should return false
+  if (kwsys::SystemTools::PathExists(std::string())) {
+    std::cerr << "Problem with PathExists(std::string())" << std::endl;
+    res = false;
+  }
+  // PathExists(x) should return true on a directory
+  if (!kwsys::SystemTools::PathExists(testNewDir)) {
+    std::cerr << "Problem with PathExists for: " << testNewDir << std::endl;
+    res = false;
+  }
+  // should work, was created as new file before
+  if (!kwsys::SystemTools::PathExists(testNewFile)) {
+    std::cerr << "Problem with PathExists for: " << testNewDir << std::endl;
+    res = false;
+  }
+
+// Reset umask
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // NOTE:  Windows doesn't support toggling _S_IREAD.
+  mode_t fullMask = _S_IWRITE;
+#else
+  // On a normal POSIX platform, we can toggle all permissions.
+  mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO;
+#endif
+  mode_t orig_umask = umask(fullMask);
+
+  // Test file permissions without umask
+  mode_t origPerm, thisPerm;
+  if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) {
+    std::cerr << "Problem with GetPermissions (1) for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) {
+    std::cerr << "Problem with SetPermissions (1) for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
+    std::cerr << "Problem with GetPermissions (2) for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  if ((thisPerm & fullMask) != 0) {
+    std::cerr << "SetPermissions failed to set permissions (1) for: "
+              << testNewFile << ": actual = " << thisPerm
+              << "; expected = " << 0 << std::endl;
+    res = false;
+  }
+
+  // While we're at it, check proper TestFileAccess functionality.
+  if (kwsys::SystemTools::TestFileAccess(testNewFile,
+                                         kwsys::TEST_FILE_WRITE)) {
+    std::cerr
+      << "TestFileAccess incorrectly indicated that this is a writable file:"
+      << testNewFile << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::TestFileAccess(testNewFile, kwsys::TEST_FILE_OK)) {
+    std::cerr
+      << "TestFileAccess incorrectly indicated that this file does not exist:"
+      << testNewFile << std::endl;
+    res = false;
+  }
+
+  // Test restoring/setting full permissions.
+  if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask)) {
+    std::cerr << "Problem with SetPermissions (2) for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
+    std::cerr << "Problem with GetPermissions (3) for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  if ((thisPerm & fullMask) != fullMask) {
+    std::cerr << "SetPermissions failed to set permissions (2) for: "
+              << testNewFile << ": actual = " << thisPerm
+              << "; expected = " << fullMask << std::endl;
+    res = false;
+  }
+
+  // Test setting file permissions while honoring umask
+  if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) {
+    std::cerr << "Problem with SetPermissions (3) for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
+    std::cerr << "Problem with GetPermissions (4) for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  if ((thisPerm & fullMask) != 0) {
+    std::cerr << "SetPermissions failed to honor umask for: " << testNewFile
+              << ": actual = " << thisPerm << "; expected = " << 0
+              << std::endl;
+    res = false;
+  }
+
+  // Restore umask
+  umask(orig_umask);
+
+  // Restore file permissions
+  if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm)) {
+    std::cerr << "Problem with SetPermissions (4) for: " << testNewFile
+              << std::endl;
+    res = false;
+  }
+
+  // Remove the test file
+  if (!kwsys::SystemTools::RemoveFile(testNewFile)) {
+    std::cerr << "Problem with RemoveFile: " << testNewFile << std::endl;
+    res = false;
+  }
+
+  std::string const testFileMissing(testNewDir + "/testMissingFile.txt");
+  if (!kwsys::SystemTools::RemoveFile(testFileMissing)) {
+    std::string const& msg = kwsys::SystemTools::GetLastSystemError();
+    std::cerr << "RemoveFile(\"" << testFileMissing << "\") failed: " << msg
+              << "\n";
+    res = false;
+  }
+
+  std::string const testFileMissingDir(testNewDir + "/missing/file.txt");
+  if (!kwsys::SystemTools::RemoveFile(testFileMissingDir)) {
+    std::string const& msg = kwsys::SystemTools::GetLastSystemError();
+    std::cerr << "RemoveFile(\"" << testFileMissingDir << "\") failed: " << msg
+              << "\n";
+    res = false;
+  }
+
+  kwsys::SystemTools::Touch(testNewFile.c_str(), true);
+  if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) {
+    std::cerr << "Problem with RemoveADirectory for: " << testNewDir
+              << std::endl;
+    res = false;
+  }
+
+#ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS
+  // Perform the same file and directory creation and deletion tests but
+  // with paths > 256 characters in length.
+
+  const std::string testNewLongDir(
+    TEST_SYSTEMTOOLS_BINARY_DIR
+    "/"
+    "012345678901234567890123456789012345678901234567890123456789"
+    "012345678901234567890123456789012345678901234567890123456789"
+    "012345678901234567890123456789012345678901234567890123456789"
+    "012345678901234567890123456789012345678901234567890123456789"
+    "01234567890123");
+  const std::string testNewLongFile(
+    testNewLongDir +
+    "/"
+    "012345678901234567890123456789012345678901234567890123456789"
+    "012345678901234567890123456789012345678901234567890123456789"
+    "012345678901234567890123456789012345678901234567890123456789"
+    "012345678901234567890123456789012345678901234567890123456789"
+    "0123456789.txt");
+
+  if (!kwsys::SystemTools::MakeDirectory(testNewLongDir)) {
+    std::cerr << "Problem with MakeDirectory for: " << testNewLongDir
+              << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true)) {
+    std::cerr << "Problem with Touch for: " << testNewLongFile << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::RemoveFile(testNewLongFile)) {
+    std::cerr << "Problem with RemoveFile: " << testNewLongFile << std::endl;
+    res = false;
+  }
+
+  kwsys::SystemTools::Touch(testNewLongFile.c_str(), true);
+  if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir)) {
+    std::cerr << "Problem with RemoveADirectory for: " << testNewLongDir
+              << std::endl;
+    res = false;
+  }
+#endif
+
+  return res;
+}
+
+//----------------------------------------------------------------------------
+static bool CheckStringOperations()
+{
+  bool res = true;
+
+  std::string test = "mary had a little lamb.";
+  if (kwsys::SystemTools::CapitalizedWords(test) !=
+      "Mary Had A Little Lamb.") {
+    std::cerr << "Problem with CapitalizedWords " << '"' << test << '"'
+              << std::endl;
+    res = false;
+  }
+
+  test = "Mary Had A Little Lamb.";
+  if (kwsys::SystemTools::UnCapitalizedWords(test) !=
+      "mary had a little lamb.") {
+    std::cerr << "Problem with UnCapitalizedWords " << '"' << test << '"'
+              << std::endl;
+    res = false;
+  }
+
+  test = "MaryHadTheLittleLamb.";
+  if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) !=
+      "Mary Had The Little Lamb.") {
+    std::cerr << "Problem with AddSpaceBetweenCapitalizedWords " << '"' << test
+              << '"' << std::endl;
+    res = false;
+  }
+
+  char* cres =
+    kwsys::SystemTools::AppendStrings("Mary Had A", " Little Lamb.");
+  if (strcmp(cres, "Mary Had A Little Lamb.")) {
+    std::cerr << "Problem with AppendStrings "
+              << "\"Mary Had A\" \" Little Lamb.\"" << std::endl;
+    res = false;
+  }
+  delete[] cres;
+
+  cres = kwsys::SystemTools::AppendStrings("Mary Had", " A ", "Little Lamb.");
+  if (strcmp(cres, "Mary Had A Little Lamb.")) {
+    std::cerr << "Problem with AppendStrings "
+              << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl;
+    res = false;
+  }
+  delete[] cres;
+
+  if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.", 'a') != 3) {
+    std::cerr << "Problem with CountChar "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+
+  cres = kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.", "aeiou");
+  if (strcmp(cres, "Mry Hd A Lttl Lmb.")) {
+    std::cerr << "Problem with RemoveChars "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+  delete[] cres;
+
+  cres = kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb.");
+  if (strcmp(cres, "A")) {
+    std::cerr << "Problem with RemoveCharsButUpperHex "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+  delete[] cres;
+
+  char* cres2 = new char[strlen("Mary Had A Little Lamb.") + 1];
+  strcpy(cres2, "Mary Had A Little Lamb.");
+  kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X');
+  if (strcmp(cres2, "MXry HXd A LXttlX LXmb.")) {
+    std::cerr << "Problem with ReplaceChars "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+  delete[] cres2;
+
+  if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.",
+                                            "Mary ")) {
+    std::cerr << "Problem with StringStartsWith "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+
+  if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.",
+                                          " Lamb.")) {
+    std::cerr << "Problem with StringEndsWith "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+
+  cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb.");
+  if (strcmp(cres, "Mary Had A Little Lamb.")) {
+    std::cerr << "Problem with DuplicateString "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+  delete[] cres;
+
+  test = "Mary Had A Little Lamb.";
+  if (kwsys::SystemTools::CropString(test, 13) != "Mary ...Lamb.") {
+    std::cerr << "Problem with CropString "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+
+  std::vector<std::string> lines;
+  kwsys::SystemTools::Split("Mary Had A Little Lamb.", lines, ' ');
+  if (lines[0] != "Mary" || lines[1] != "Had" || lines[2] != "A" ||
+      lines[3] != "Little" || lines[4] != "Lamb.") {
+    std::cerr << "Problem with Split "
+              << "\"Mary Had A Little Lamb.\"" << std::endl;
+    res = false;
+  }
+
+  if (kwsys::SystemTools::ConvertToWindowsOutputPath(
+        "L://Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+      "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") {
+    std::cerr << "Problem with ConvertToWindowsOutputPath "
+              << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl;
+    res = false;
+  }
+
+  if (kwsys::SystemTools::ConvertToWindowsOutputPath(
+        "//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+      "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") {
+    std::cerr << "Problem with ConvertToWindowsOutputPath "
+              << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+              << std::endl;
+    res = false;
+  }
+
+  if (kwsys::SystemTools::ConvertToUnixOutputPath(
+        "//Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+      "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo") {
+    std::cerr << "Problem with ConvertToUnixOutputPath "
+              << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl;
+    res = false;
+  }
+
+  return res;
+}
+
+//----------------------------------------------------------------------------
+
+static bool CheckPutEnv(const std::string& env, const char* name,
+                        const char* value)
+{
+  if (!kwsys::SystemTools::PutEnv(env)) {
+    std::cerr << "PutEnv(\"" << env << "\") failed!" << std::endl;
+    return false;
+  }
+  std::string v = "(null)";
+  kwsys::SystemTools::GetEnv(name, v);
+  if (v != value) {
+    std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not \""
+              << value << "\"!" << std::endl;
+    return false;
+  }
+  return true;
+}
+
+static bool CheckUnPutEnv(const char* env, const char* name)
+{
+  if (!kwsys::SystemTools::UnPutEnv(env)) {
+    std::cerr << "UnPutEnv(\"" << env << "\") failed!" << std::endl;
+    return false;
+  }
+  std::string v;
+  if (kwsys::SystemTools::GetEnv(name, v)) {
+    std::cerr << "GetEnv(\"" << name << "\") returned \"" << v
+              << "\", not (null)!" << std::endl;
+    return false;
+  }
+  return true;
+}
+
+static bool CheckEnvironmentOperations()
+{
+  bool res = true;
+  res &= CheckPutEnv("A=B", "A", "B");
+  res &= CheckPutEnv("B=C", "B", "C");
+  res &= CheckPutEnv("C=D", "C", "D");
+  res &= CheckPutEnv("D=E", "D", "E");
+  res &= CheckUnPutEnv("A", "A");
+  res &= CheckUnPutEnv("B=", "B");
+  res &= CheckUnPutEnv("C=D", "C");
+  /* Leave "D=E" in environment so a memory checker can test for leaks.  */
+  return res;
+}
+
+static bool CheckRelativePath(const std::string& local,
+                              const std::string& remote,
+                              const std::string& expected)
+{
+  std::string result = kwsys::SystemTools::RelativePath(local, remote);
+  if (!kwsys::SystemTools::ComparePath(expected, result)) {
+    std::cerr << "RelativePath(" << local << ", " << remote << ")  yielded "
+              << result << " instead of " << expected << std::endl;
+    return false;
+  }
+  return true;
+}
+
+static bool CheckRelativePaths()
+{
+  bool res = true;
+  res &= CheckRelativePath("/usr/share", "/bin/bash", "../../bin/bash");
+  res &= CheckRelativePath("/usr/./share/", "/bin/bash", "../../bin/bash");
+  res &= CheckRelativePath("/usr//share/", "/bin/bash", "../../bin/bash");
+  res &=
+    CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash");
+  res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin");
+  return res;
+}
+
+static bool CheckCollapsePath(const std::string& path,
+                              const std::string& expected)
+{
+  std::string result = kwsys::SystemTools::CollapseFullPath(path);
+  if (!kwsys::SystemTools::ComparePath(expected, result)) {
+    std::cerr << "CollapseFullPath(" << path << ")  yielded " << result
+              << " instead of " << expected << std::endl;
+    return false;
+  }
+  return true;
+}
+
+static bool CheckCollapsePath()
+{
+  bool res = true;
+  res &= CheckCollapsePath("/usr/share/*", "/usr/share/*");
+  res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*");
+  return res;
+}
+
+static std::string StringVectorToString(const std::vector<std::string>& vec)
+{
+  std::stringstream ss;
+  ss << "vector(";
+  for (std::vector<std::string>::const_iterator i = vec.begin();
+       i != vec.end(); ++i) {
+    if (i != vec.begin()) {
+      ss << ", ";
+    }
+    ss << *i;
+  }
+  ss << ")";
+  return ss.str();
+}
+
+static bool CheckGetPath()
+{
+  const char* envName = "S";
+#ifdef _WIN32
+  const char* envValue = "C:\\Somewhere\\something;D:\\Temp";
+#else
+  const char* envValue = "/Somewhere/something:/tmp";
+#endif
+  const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]";
+
+  std::vector<std::string> originalPathes;
+  originalPathes.push_back(registryPath);
+
+  std::vector<std::string> expectedPathes;
+  expectedPathes.push_back(registryPath);
+#ifdef _WIN32
+  expectedPathes.push_back("C:/Somewhere/something");
+  expectedPathes.push_back("D:/Temp");
+#else
+  expectedPathes.push_back("/Somewhere/something");
+  expectedPathes.push_back("/tmp");
+#endif
+
+  bool res = true;
+  res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue);
+
+  std::vector<std::string> pathes = originalPathes;
+  kwsys::SystemTools::GetPath(pathes, envName);
+
+  if (pathes != expectedPathes) {
+    std::cerr << "GetPath(" << StringVectorToString(originalPathes) << ", "
+              << envName << ")  yielded " << StringVectorToString(pathes)
+              << " instead of " << StringVectorToString(expectedPathes)
+              << std::endl;
+    res = false;
+  }
+
+  res &= CheckUnPutEnv(envName, envName);
+  return res;
+}
+
+static bool CheckFind()
+{
+  bool res = true;
+  const std::string testFindFileName("testFindFile.txt");
+  const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/" +
+                                 testFindFileName);
+
+  if (!kwsys::SystemTools::Touch(testFindFile.c_str(), true)) {
+    std::cerr << "Problem with Touch for: " << testFindFile << std::endl;
+    // abort here as the existence of the file only makes the test meaningful
+    return false;
+  }
+
+  std::vector<std::string> searchPaths;
+  searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR);
+  if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true)
+        .empty()) {
+    std::cerr << "Problem with FindFile without system paths for: "
+              << testFindFileName << std::endl;
+    res = false;
+  }
+  if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, false)
+        .empty()) {
+    std::cerr << "Problem with FindFile with system paths for: "
+              << testFindFileName << std::endl;
+    res = false;
+  }
+
+  return res;
+}
+
+static bool CheckGetLineFromStream()
+{
+  const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR
+                                                 "/README.rst");
+
+  kwsys::ifstream file(fileWithFiveCharsOnFirstLine.c_str(), std::ios::in);
+
+  if (!file) {
+    std::cerr << "Problem opening: " << fileWithFiveCharsOnFirstLine
+              << std::endl;
+    return false;
+  }
+
+  std::string line;
+  bool has_newline = false;
+  bool result;
+
+  file.seekg(0, std::ios::beg);
+  result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1);
+  if (!result || line.size() != 5) {
+    std::cerr << "First line does not have five characters: " << line.size()
+              << std::endl;
+    return false;
+  }
+
+  file.seekg(0, std::ios::beg);
+  result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1);
+  if (!result || line.size() != 5) {
+    std::cerr << "First line does not have five characters after rewind: "
+              << line.size() << std::endl;
+    return false;
+  }
+
+  bool ret = true;
+
+  for (size_t size = 1; size <= 5; ++size) {
+    file.seekg(0, std::ios::beg);
+    result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline,
+                                                   static_cast<long>(size));
+    if (!result || line.size() != size) {
+      std::cerr << "Should have read " << size << " characters but got "
+                << line.size() << std::endl;
+      ret = false;
+    }
+  }
+
+  return ret;
+}
+
+//----------------------------------------------------------------------------
+int testSystemTools(int, char* [])
+{
+  bool res = true;
+
+  int cc;
+  for (cc = 0; toUnixPaths[cc][0]; cc++) {
+    res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]);
+  }
+
+  // Special check for ~
+  std::string output;
+  if (kwsys::SystemTools::GetEnv("HOME", output)) {
+    output += "/foo bar/lala";
+    res &= CheckConvertToUnixSlashes("~/foo bar/lala", output);
+  }
+
+  for (cc = 0; checkEscapeChars[cc][0]; cc++) {
+    res &= CheckEscapeChars(checkEscapeChars[cc][0], checkEscapeChars[cc][1],
+                            *checkEscapeChars[cc][2], checkEscapeChars[cc][3]);
+  }
+
+  res &= CheckFileOperations();
+
+  res &= CheckStringOperations();
+
+  res &= CheckEnvironmentOperations();
+
+  res &= CheckRelativePaths();
+
+  res &= CheckCollapsePath();
+
+  res &= CheckGetPath();
+
+  res &= CheckFind();
+
+  res &= CheckGetLineFromStream();
+
+  return res ? 0 : 1;
+}
diff --git a/thirdparty/KWSys/adios2sys/testSystemTools.h.in b/thirdparty/KWSys/adios2sys/testSystemTools.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..022e36e2f444ce4e77d4ae35bdce600e1f9aaace
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testSystemTools.h.in
@@ -0,0 +1,12 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_testSystemtools_h
+#define @KWSYS_NAMESPACE@_testSystemtools_h
+
+#define EXECUTABLE_OUTPUT_PATH "@CMAKE_CURRENT_BINARY_DIR@"
+
+#define TEST_SYSTEMTOOLS_SOURCE_DIR "@TEST_SYSTEMTOOLS_SOURCE_DIR@"
+#define TEST_SYSTEMTOOLS_BINARY_DIR "@TEST_SYSTEMTOOLS_BINARY_DIR@"
+#cmakedefine KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS
+
+#endif
diff --git a/thirdparty/KWSys/adios2sys/testTerminal.c b/thirdparty/KWSys/adios2sys/testTerminal.c
new file mode 100644
index 0000000000000000000000000000000000000000..f6c1eddb7b159a67cc86b7e7d1628a0f8d320214
--- /dev/null
+++ b/thirdparty/KWSys/adios2sys/testTerminal.c
@@ -0,0 +1,22 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Terminal.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#include "Terminal.h.in"
+#endif
+
+int testTerminal(int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  kwsysTerminal_cfprintf(kwsysTerminal_Color_ForegroundYellow |
+                           kwsysTerminal_Color_BackgroundBlue |
+                           kwsysTerminal_Color_AssumeTTY,
+                         stdout, "Hello %s!", "World");
+  fprintf(stdout, "\n");
+  return 0;
+}
diff --git a/thirdparty/KWSys/update.sh b/thirdparty/KWSys/update.sh
new file mode 100755
index 0000000000000000000000000000000000000000..44b7d9cba938968d4e8448c6d0fd1485d00d7882
--- /dev/null
+++ b/thirdparty/KWSys/update.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="KWSys"
+readonly ownership="KWSys Upstream <kwrobot@kitware.com>"
+readonly subtree="thirdparty/KWSys/adios2sys"
+#readonly repo="https://gitlab.kitware.com/utils/kwsys.git"
+#readonly tag="0c4e58ec"
+
+# This commit contains a patch so suppress noisy warnings.  Use 'master' off
+# the main repo instead once its been merged
+readonly repo="https://gitlab.kitware.com/chuck.atkins/kwsys.git"
+readonly tag="0c4e58ec"
+
+readonly shortlog="true"
+readonly paths="
+"
+
+extract_source () {
+    git_archive
+}
+
+. "${BASH_SOURCE%/*}/../update-common.sh"
diff --git a/thirdparty/update-common.sh b/thirdparty/update-common.sh
new file mode 100755
index 0000000000000000000000000000000000000000..3b8358e0114b9afc48c104d9afbbd7ba7de48a90
--- /dev/null
+++ b/thirdparty/update-common.sh
@@ -0,0 +1,169 @@
+#=============================================================================
+# Copyright 2015-2016 Kitware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+########################################################################
+# Script for updating third party packages.
+#
+# This script should be sourced in a project-specific script which sets
+# the following variables:
+#
+#   name
+#       The name of the project.
+#   ownership
+#       A git author name/email for the commits.
+#   subtree
+#       The location of the thirdparty package within the main source
+#       tree.
+#   repo
+#       The git repository to use as upstream.
+#   tag
+#       The tag, branch or commit hash to use for upstream.
+#   shortlog
+#       Optional.  Set to 'true' to get a shortlog in the commit message.
+#
+# Additionally, an "extract_source" function must be defined. It will be
+# run within the checkout of the project on the requested tag. It should
+# should place the desired tree into $extractdir/$name-reduced. This
+# directory will be used as the newest commit for the project.
+#
+# For convenience, the function may use the "git_archive" function which
+# does a standard "git archive" extraction using the (optional) "paths"
+# variable to only extract a subset of the source tree.
+########################################################################
+
+########################################################################
+# Utility functions
+########################################################################
+git_archive () {
+    git archive --worktree-attributes --prefix="$name-reduced/" HEAD -- $paths | \
+        tar -C "$extractdir" -x
+}
+
+die () {
+    echo >&2 "$@"
+    exit 1
+}
+
+warn () {
+    echo >&2 "warning: $@"
+}
+
+readonly regex_date='20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
+readonly basehash_regex="$name $regex_date ([0-9a-f]*)"
+readonly basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
+readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )"
+
+########################################################################
+# Sanity checking
+########################################################################
+[ -n "$name" ] || \
+    die "'name' is empty"
+[ -n "$ownership" ] || \
+    die "'ownership' is empty"
+[ -n "$subtree" ] || \
+    die "'subtree' is empty"
+[ -n "$repo" ] || \
+    die "'repo' is empty"
+[ -n "$tag" ] || \
+    die "'tag' is empty"
+[ -n "$basehash" ] || \
+    warn "'basehash' is empty; performing initial import"
+readonly do_shortlog="${shortlog-false}"
+
+readonly workdir="$PWD/work"
+readonly upstreamdir="$workdir/upstream"
+readonly extractdir="$workdir/extract"
+
+[ -d "$workdir" ] && \
+    die "error: workdir '$workdir' already exists"
+
+trap "rm -rf '$workdir'" EXIT
+
+# Get upstream
+git clone "$repo" "$upstreamdir"
+
+if [ -n "$basehash" ]; then
+    # Use the existing package's history
+    git worktree add "$extractdir" "$basehash"
+    # Clear out the working tree
+    pushd "$extractdir"
+    git ls-files | xargs rm -v
+    find . -type d -empty -delete
+    popd
+else
+    # Create a repo to hold this package's history
+    mkdir -p "$extractdir"
+    git -C "$extractdir" init
+fi
+
+# Extract the subset of upstream we care about
+pushd "$upstreamdir"
+git checkout "$tag"
+readonly upstream_hash="$( git rev-parse HEAD )"
+readonly upstream_hash_short="$( git rev-parse --short=8 "$upstream_hash" )"
+readonly upstream_datetime="$( git rev-list "$upstream_hash" --format='%ci' -n 1 | grep -e "^$regex_date" )"
+readonly upstream_date="$( echo "$upstream_datetime" | grep -o -e "$regex_date" )"
+if $do_shortlog && [ -n "$basehash" ]; then
+    readonly commit_shortlog="
+
+Upstream Shortlog
+-----------------
+
+$( git shortlog --no-merges --abbrev=8 --format='%h %s' "$upstream_old_short".."$upstream_hash" )"
+else
+    readonly commit_shortlog=""
+fi
+extract_source || \
+    die "failed to extract source"
+popd
+
+[ -d "$extractdir/$name-reduced" ] || \
+    die "expected directory to extract does not exist"
+readonly commit_summary="$name $upstream_date ($upstream_hash_short)"
+
+# Commit the subset
+pushd "$extractdir"
+mv -v "$name-reduced/"* .
+rmdir "$name-reduced/"
+git add -A .
+git commit -n --author="$ownership" --date="$upstream_datetime" -F - <<-EOF
+$commit_summary
+
+Code extracted from:
+
+    $repo
+
+at commit $upstream_hash ($tag).$commit_shortlog
+EOF
+git branch -f "upstream-$name"
+popd
+
+# Merge the subset into this repository
+if [ -n "$basehash" ]; then
+    git merge --log -s recursive "-Xsubtree=$subtree/" --no-commit "upstream-$name"
+else
+    unrelated_histories_flag=""
+    if git merge --help | grep -q -e allow-unrelated-histories; then
+        unrelated_histories_flag="--allow-unrelated-histories "
+    fi
+    readonly unrelated_histories_flag
+
+    git fetch "$extractdir" "upstream-$name:upstream-$name"
+    git merge --log -s ours --no-commit $unrelated_histories_flag "upstream-$name"
+    git read-tree -u --prefix="$subtree/" "upstream-$name"
+fi
+git commit --no-edit
+git branch -d "upstream-$name"