summaryrefslogtreecommitdiffstats
path: root/Source/kwsys
diff options
context:
space:
mode:
Diffstat (limited to 'Source/kwsys')
-rw-r--r--Source/kwsys/.gitattributes12
-rw-r--r--Source/kwsys/Base64.c279
-rw-r--r--Source/kwsys/Base64.h.in122
-rw-r--r--Source/kwsys/CMakeLists.txt1038
-rw-r--r--Source/kwsys/CONTRIBUTING.rst35
-rw-r--r--Source/kwsys/CTestConfig.cmake17
-rw-r--r--Source/kwsys/CTestCustom.cmake.in14
-rw-r--r--Source/kwsys/CommandLineArguments.cxx857
-rw-r--r--Source/kwsys/CommandLineArguments.hxx.in276
-rw-r--r--Source/kwsys/Configure.h.in136
-rw-r--r--Source/kwsys/Configure.hxx.in31
-rw-r--r--Source/kwsys/Copyright.txt31
-rw-r--r--Source/kwsys/Directory.cxx260
-rw-r--r--Source/kwsys/Directory.hxx.in81
-rw-r--r--Source/kwsys/DynamicLoader.cxx531
-rw-r--r--Source/kwsys/DynamicLoader.hxx.in102
-rw-r--r--Source/kwsys/Encoding.h.in79
-rw-r--r--Source/kwsys/Encoding.hxx.in77
-rw-r--r--Source/kwsys/EncodingC.c85
-rw-r--r--Source/kwsys/EncodingCXX.cxx185
-rw-r--r--Source/kwsys/ExtraTest.cmake.in1
-rw-r--r--Source/kwsys/FStream.cxx78
-rw-r--r--Source/kwsys/FStream.hxx.in194
-rw-r--r--Source/kwsys/Glob.cxx559
-rw-r--r--Source/kwsys/Glob.hxx.in152
-rw-r--r--Source/kwsys/IOStream.cxx250
-rw-r--r--Source/kwsys/IOStream.hxx.in136
-rw-r--r--Source/kwsys/MD5.c523
-rw-r--r--Source/kwsys/MD5.h.in107
-rw-r--r--Source/kwsys/Process.h.in469
-rw-r--r--Source/kwsys/ProcessUNIX.c3071
-rw-r--r--Source/kwsys/ProcessWin32.c3030
-rw-r--r--Source/kwsys/README.txt12
-rw-r--r--Source/kwsys/RegularExpression.cxx1244
-rw-r--r--Source/kwsys/RegularExpression.hxx.in443
-rw-r--r--Source/kwsys/SharedForward.h.in944
-rw-r--r--Source/kwsys/String.c115
-rw-r--r--Source/kwsys/String.h.in67
-rw-r--r--Source/kwsys/String.hxx.in65
-rw-r--r--Source/kwsys/System.c301
-rw-r--r--Source/kwsys/System.h.in69
-rw-r--r--Source/kwsys/SystemInformation.cxx5489
-rw-r--r--Source/kwsys/SystemInformation.hxx.in152
-rw-r--r--Source/kwsys/SystemTools.cxx5612
-rw-r--r--Source/kwsys/SystemTools.hxx.in1005
-rw-r--r--Source/kwsys/Terminal.c445
-rw-r--r--Source/kwsys/Terminal.h.in159
-rw-r--r--Source/kwsys/hash_fun.hxx.in149
-rw-r--r--Source/kwsys/hash_map.hxx.in375
-rw-r--r--Source/kwsys/hash_set.hxx.in359
-rw-r--r--Source/kwsys/hashtable.hxx.in997
-rwxr-xr-xSource/kwsys/kwsysHeaderDump.pl50
-rw-r--r--Source/kwsys/kwsysPlatformTests.cmake219
-rw-r--r--Source/kwsys/kwsysPlatformTestsC.c100
-rw-r--r--Source/kwsys/kwsysPlatformTestsCXX.cxx351
-rw-r--r--Source/kwsys/kwsysPrivate.h41
-rw-r--r--Source/kwsys/testCommandLineArguments.cxx187
-rw-r--r--Source/kwsys/testCommandLineArguments1.cxx108
-rw-r--r--Source/kwsys/testDynamicLoader.cxx128
-rw-r--r--Source/kwsys/testDynload.c22
-rw-r--r--Source/kwsys/testEncode.c76
-rw-r--r--Source/kwsys/testEncoding.cxx198
-rw-r--r--Source/kwsys/testFStream.cxx138
-rw-r--r--Source/kwsys/testFail.c35
-rw-r--r--Source/kwsys/testHashSTL.cxx74
-rw-r--r--Source/kwsys/testIOS.cxx164
-rw-r--r--Source/kwsys/testProcess.c755
-rw-r--r--Source/kwsys/testSharedForward.c.in36
-rw-r--r--Source/kwsys/testSystemInformation.cxx119
-rw-r--r--Source/kwsys/testSystemTools.binbin0 -> 766 bytes
-rw-r--r--Source/kwsys/testSystemTools.cxx1080
-rw-r--r--Source/kwsys/testSystemTools.h.in21
-rw-r--r--Source/kwsys/testTerminal.c31
73 files changed, 34753 insertions, 0 deletions
diff --git a/Source/kwsys/.gitattributes b/Source/kwsys/.gitattributes
new file mode 100644
index 0000000..a9c4e77
--- /dev/null
+++ b/Source/kwsys/.gitattributes
@@ -0,0 +1,12 @@
+.git* export-ignore
+
+/CONTRIBUTING.rst conflict-marker-size=78
+
+*.c whitespace=tab-in-indent,no-lf-at-eof
+*.h whitespace=tab-in-indent,no-lf-at-eof
+*.h.in whitespace=tab-in-indent,no-lf-at-eof
+*.cxx whitespace=tab-in-indent,no-lf-at-eof
+*.hxx whitespace=tab-in-indent,no-lf-at-eof
+*.hxx.in whitespace=tab-in-indent,no-lf-at-eof
+*.txt whitespace=tab-in-indent,no-lf-at-eof
+*.cmake whitespace=tab-in-indent,no-lf-at-eof
diff --git a/Source/kwsys/Base64.c b/Source/kwsys/Base64.c
new file mode 100644
index 0000000..4b8ede2
--- /dev/null
+++ b/Source/kwsys/Base64.c
@@ -0,0 +1,279 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/Base64.h.in b/Source/kwsys/Base64.h.in
new file mode 100644
index 0000000..36ed3cc
--- /dev/null
+++ b/Source/kwsys/Base64.h.in
@@ -0,0 +1,122 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
new file mode 100644
index 0000000..39b03b3
--- /dev/null
+++ b/Source/kwsys/CMakeLists.txt
@@ -0,0 +1,1038 @@
+#=============================================================================
+# KWSys - Kitware System Library
+# Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# 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)
+IF(POLICY CMP0025)
+ CMAKE_POLICY(SET CMP0025 NEW)
+ENDIF()
+IF(POLICY CMP0056)
+ CMAKE_POLICY(SET CMP0056 NEW)
+ENDIF()
+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)
+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()
+
+# 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_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()
+
+#-----------------------------------------------------------------------------
+# 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
+ )
+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 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()
+ 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 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_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 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/Source/kwsys/CONTRIBUTING.rst b/Source/kwsys/CONTRIBUTING.rst
new file mode 100644
index 0000000..960eea4
--- /dev/null
+++ b/Source/kwsys/CONTRIBUTING.rst
@@ -0,0 +1,35 @@
+Contributing to KWSys
+*********************
+
+Overview
+========
+
+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.
+
+Please visit
+
+ http://public.kitware.com/Wiki/KWSys/Git
+
+to contribute changes directly to KWSys upstream. Once changes are
+reviewed, tested, and integrated there then the copies of KWSys within
+dependent projects can be updated to get the changes.
+
+Issues
+======
+
+KWSys has no independent issue tracker. After encountering an issue
+(bug) please try to submit a patch using the above instructions.
+Otherwise please report the issue to the tracker for the project that
+hosts the copy of KWSys in which the problem was found.
+
+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/Source/kwsys/CTestConfig.cmake b/Source/kwsys/CTestConfig.cmake
new file mode 100644
index 0000000..d977b47
--- /dev/null
+++ b/Source/kwsys/CTestConfig.cmake
@@ -0,0 +1,17 @@
+#=============================================================================
+# KWSys - Kitware System Library
+# Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+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=PublicDashboard")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Source/kwsys/CTestCustom.cmake.in b/Source/kwsys/CTestCustom.cmake.in
new file mode 100644
index 0000000..760221b
--- /dev/null
+++ b/Source/kwsys/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/Source/kwsys/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx
new file mode 100644
index 0000000..f713294
--- /dev/null
+++ b/Source/kwsys/CommandLineArguments.cxx
@@ -0,0 +1,857 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 <vector>
+#include <map>
+#include <set>
+#include <sstream>
+#include <iostream>
+
+#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/Source/kwsys/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in
new file mode 100644
index 0000000..e4f6d02
--- /dev/null
+++ b/Source/kwsys/CommandLineArguments.hxx.in
@@ -0,0 +1,276 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/Configure.h.in b/Source/kwsys/Configure.h.in
new file mode 100644
index 0000000..cd2d965
--- /dev/null
+++ b/Source/kwsys/Configure.h.in
@@ -0,0 +1,136 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in
new file mode 100644
index 0000000..ff8e49d
--- /dev/null
+++ b/Source/kwsys/Configure.hxx.in
@@ -0,0 +1,31 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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@
+
+/* 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
+#endif
+
+#endif
diff --git a/Source/kwsys/Copyright.txt b/Source/kwsys/Copyright.txt
new file mode 100644
index 0000000..1549a7d
--- /dev/null
+++ b/Source/kwsys/Copyright.txt
@@ -0,0 +1,31 @@
+KWSys - Kitware System Library
+Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+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 names of Kitware, Inc., the Insight Software Consortium,
+ nor the names of their 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.
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
new file mode 100644
index 0000000..c549792
--- /dev/null
+++ b/Source/kwsys/Directory.cxx
@@ -0,0 +1,260 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 "Directory.hxx.in"
+# include "Configure.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 microsoft compilers
+
+#if defined(_MSC_VER) || defined(__WATCOMC__)
+#include <windows.h>
+#include <io.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace KWSYS_NAMESPACE
+{
+
+bool Directory::Load(const std::string& name)
+{
+ this->Clear();
+#if _MSC_VER < 1300
+ long srchHandle;
+#else
+ 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((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(srchHandle, &data) != -1 );
+ this->Internal->Path = name;
+ return _findclose(srchHandle) != -1;
+}
+
+unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
+{
+#if _MSC_VER < 1300
+ long srchHandle;
+#else
+ 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((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(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/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in
new file mode 100644
index 0000000..e68f337
--- /dev/null
+++ b/Source/kwsys/Directory.hxx.in
@@ -0,0 +1,81 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx
new file mode 100644
index 0000000..1941d96
--- /dev/null
+++ b/Source/kwsys/DynamicLoader.cxx
@@ -0,0 +1,531 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 "DynamicLoader.hxx.in"
+# include "Configure.hxx.in"
+#endif
+
+// This file is actually 3 different implementations.
+// 1. HP machines which uses shl_load
+// 2. Mac OS X 10.2.x and earlier which uses NSLinkModule
+// 3. Windows which uses LoadLibrary
+// 4. Most unix systems (including Mac OS X 10.3 and later) which use dlopen
+// (default) Each part of the ifdef contains a complete implementation for
+// the static methods of DynamicLoader.
+
+// ---------------------------------------------------------------
+// 1. Implementation for HPUX machines
+#ifdef __hpux
+#include <errno.h>
+#include <dl.h>
+#define DYNAMICLOADER_DEFINED 1
+
+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
+
+#endif //__hpux
+
+
+// ---------------------------------------------------------------
+// 2. Implementation for Mac OS X 10.2.x and earlier
+#ifdef __APPLE__
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+#include <string.h> // for strlen
+#include <mach-o/dyld.h>
+#define DYNAMICLOADER_DEFINED 1
+
+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
+
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1030
+#endif // __APPLE__
+
+// ---------------------------------------------------------------
+// 3. Implementation for Windows win32 code but not cygwin
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#define DYNAMICLOADER_DEFINED 1
+
+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
+
+#endif //_WIN32
+
+// ---------------------------------------------------------------
+// 4. Implementation for BeOS
+#if defined __BEOS__
+
+#include <string.h> // for strerror()
+
+#include <be/kernel/image.h>
+#include <be/support/Errors.h>
+
+#define DYNAMICLOADER_DEFINED 1
+
+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
+#endif
+
+// ---------------------------------------------------------------
+// 5. Implementation for systems without dynamic libs
+// __gnu_blrts__ is IBM BlueGene/L
+// __LIBCATAMOUNT__ is defined on Catamount on Cray compute nodes
+#if defined(__gnu_blrts__) || defined(__LIBCATAMOUNT__) || defined(__CRAYXT_COMPUTE_LINUX_TARGET)
+#include <string.h> // for strerror()
+#define DYNAMICLOADER_DEFINED 1
+
+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
+#endif
+
+#ifdef __MINT__
+#define DYNAMICLOADER_DEFINED 1
+#define _GNU_SOURCE /* for program_invocation_name */
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <dld.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
+#endif
+
+// ---------------------------------------------------------------
+// 6. Implementation for default UNIX machines.
+// if nothing has been defined then use this
+#ifndef DYNAMICLOADER_DEFINED
+#define DYNAMICLOADER_DEFINED 1
+// Setup for most unix machines
+#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/Source/kwsys/DynamicLoader.hxx.in b/Source/kwsys/DynamicLoader.hxx.in
new file mode 100644
index 0000000..1e4a912
--- /dev/null
+++ b/Source/kwsys/DynamicLoader.hxx.in
@@ -0,0 +1,102 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/Encoding.h.in b/Source/kwsys/Encoding.h.in
new file mode 100644
index 0000000..591c5a8
--- /dev/null
+++ b/Source/kwsys/Encoding.h.in
@@ -0,0 +1,79 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/Encoding.hxx.in b/Source/kwsys/Encoding.hxx.in
new file mode 100644
index 0000000..87b1c21
--- /dev/null
+++ b/Source/kwsys/Encoding.hxx.in
@@ -0,0 +1,77 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 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);
+
+#endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING
+
+}; // class Encoding
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/EncodingC.c b/Source/kwsys/EncodingC.c
new file mode 100644
index 0000000..32b9bff
--- /dev/null
+++ b/Source/kwsys/EncodingC.c
@@ -0,0 +1,85 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx
new file mode 100644
index 0000000..597d4bd
--- /dev/null
+++ b/Source/kwsys/EncodingCXX.cxx
@@ -0,0 +1,185 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#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.hxx.in"
+# include "Encoding.h.in"
+#endif
+
+#include <vector>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+# pragma warning (disable: 4786)
+#endif
+
+// Windows API.
+#if defined(_WIN32)
+# include <windows.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)
+{
+ return ToWide(str.c_str());
+}
+
+std::string Encoding::ToNarrow(const std::wstring& str)
+{
+ return ToNarrow(str.c_str());
+}
+
+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;
+}
+#endif // KWSYS_STL_HAS_WSTRING
+
+} // namespace KWSYS_NAMESPACE
diff --git a/Source/kwsys/ExtraTest.cmake.in b/Source/kwsys/ExtraTest.cmake.in
new file mode 100644
index 0000000..e8c0a1c
--- /dev/null
+++ b/Source/kwsys/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/Source/kwsys/FStream.cxx b/Source/kwsys/FStream.cxx
new file mode 100644
index 0000000..5a30997
--- /dev/null
+++ b/Source/kwsys/FStream.cxx
@@ -0,0 +1,78 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/FStream.hxx.in b/Source/kwsys/FStream.hxx.in
new file mode 100644
index 0000000..681e4d8
--- /dev/null
+++ b/Source/kwsys/FStream.hxx.in
@@ -0,0 +1,194 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_FStream_hxx
+#define @KWSYS_NAMESPACE@_FStream_hxx
+
+#include <@KWSYS_NAMESPACE@/Encoding.hxx>
+#include <fstream>
+
+namespace @KWSYS_NAMESPACE@
+{
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# if defined(_NOEXCEPT)
+# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT _NOEXCEPT
+# else
+# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+# endif
+ template<typename CharType,typename Traits>
+ class basic_filebuf : public std::basic_filebuf<CharType,Traits>
+ {
+ public:
+ typedef std::basic_filebuf<CharType,Traits> my_base_type;
+ basic_filebuf *open(char const *s,std::ios_base::openmode mode)
+ {
+ return static_cast<basic_filebuf*>(
+ my_base_type::open(Encoding::ToWide(s).c_str(), mode)
+ );
+ }
+ };
+
+ template<typename CharType,typename Traits = std::char_traits<CharType> >
+ class basic_ifstream : public std::basic_istream<CharType,Traits>
+ {
+ public:
+ typedef basic_filebuf<CharType,Traits> internal_buffer_type;
+ typedef std::basic_istream<CharType,Traits> internal_stream_type;
+
+ basic_ifstream() : internal_stream_type(new internal_buffer_type())
+ {
+ 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())
+ {
+ 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)
+ {
+ if(!buf_->open(file_name,mode | std::ios_base::in))
+ {
+ this->setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+ }
+ bool is_open()
+ {
+ return buf_->is_open();
+ }
+ bool is_open() const
+ {
+ return buf_->is_open();
+ }
+ void close()
+ {
+ if(!buf_->close())
+ {
+ this->setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+ }
+
+ internal_buffer_type *rdbuf() const
+ {
+ return buf_;
+ }
+
+ ~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+ {
+ buf_->close();
+ delete buf_;
+ }
+
+ private:
+ internal_buffer_type* buf_;
+};
+
+template<typename CharType,typename Traits = std::char_traits<CharType> >
+class basic_ofstream : public std::basic_ostream<CharType,Traits>
+{
+ public:
+ typedef basic_filebuf<CharType,Traits> internal_buffer_type;
+ typedef std::basic_ostream<CharType,Traits> internal_stream_type;
+
+ basic_ofstream() : internal_stream_type(new internal_buffer_type())
+ {
+ 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())
+ {
+ 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)
+ {
+ if(!buf_->open(file_name,mode | std::ios_base::out))
+ {
+ this->setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+ }
+ bool is_open()
+ {
+ return buf_->is_open();
+ }
+ bool is_open() const
+ {
+ return buf_->is_open();
+ }
+ void close()
+ {
+ if(!buf_->close())
+ {
+ this->setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+ }
+
+ internal_buffer_type *rdbuf() const
+ {
+ return buf_.get();
+ }
+ ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT
+ {
+ buf_->close();
+ delete buf_;
+ }
+
+ private:
+ internal_buffer_type* buf_;
+};
+
+ 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).
+ BOM ReadBOM(std::istream& in);
+ }
+}
+
+#endif
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
new file mode 100644
index 0000000..9d63459
--- /dev/null
+++ b/Source/kwsys/Glob.cxx
@@ -0,0 +1,559 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 "Glob.hxx.in"
+# include "Directory.hxx.in"
+# include "Configure.hxx.in"
+# include "RegularExpression.hxx.in"
+# include "SystemTools.hxx.in"
+#endif
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#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/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
new file mode 100644
index 0000000..ffee9ca
--- /dev/null
+++ b/Source/kwsys/Glob.hxx.in
@@ -0,0 +1,152 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/IOStream.cxx b/Source/kwsys/IOStream.cxx
new file mode 100644
index 0000000..81c6a73
--- /dev/null
+++ b/Source/kwsys/IOStream.cxx
@@ -0,0 +1,250 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/IOStream.hxx.in b/Source/kwsys/IOStream.hxx.in
new file mode 100644
index 0000000..c101909
--- /dev/null
+++ b/Source/kwsys/IOStream.hxx.in
@@ -0,0 +1,136 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/MD5.c b/Source/kwsys/MD5.c
new file mode 100644
index 0000000..b75acb2
--- /dev/null
+++ b/Source/kwsys/MD5.c
@@ -0,0 +1,523 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/MD5.h.in b/Source/kwsys/MD5.h.in
new file mode 100644
index 0000000..3334431
--- /dev/null
+++ b/Source/kwsys/MD5.h.in
@@ -0,0 +1,107 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in
new file mode 100644
index 0000000..96563a2
--- /dev/null
+++ b/Source/kwsys/Process.h.in
@@ -0,0 +1,469 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
new file mode 100644
index 0000000..b577982
--- /dev/null
+++ b/Source/kwsys/ProcessUNIX.c
@@ -0,0 +1,3071 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 <stddef.h> /* ptrdiff_t */
+#include <stdio.h> /* snprintf */
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* strdup, strerror, memset */
+#include <sys/time.h> /* struct timeval */
+#include <sys/types.h> /* pid_t, fd_set */
+#include <sys/wait.h> /* waitpid */
+#include <sys/stat.h> /* open mode */
+#include <unistd.h> /* pipe, close, fork, execvp, select, _exit */
+#include <fcntl.h> /* fcntl */
+#include <errno.h> /* errno */
+#include <time.h> /* gettimeofday */
+#include <signal.h> /* sigaction */
+#include <dirent.h> /* DIR, dirent */
+#include <ctype.h> /* isspace */
+#include <assert.h> /* assert */
+
+#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/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
new file mode 100644
index 0000000..2b93e69
--- /dev/null
+++ b/Source/kwsys/ProcessWin32.c
@@ -0,0 +1,3030 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 "Process.h.in"
+# include "Encoding.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 <string.h> /* strlen, strdup */
+#include <stdio.h> /* sprintf */
+#include <io.h> /* _unlink */
+#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/Source/kwsys/README.txt b/Source/kwsys/README.txt
new file mode 100644
index 0000000..b8191f7
--- /dev/null
+++ b/Source/kwsys/README.txt
@@ -0,0 +1,12 @@
+KWSys provides a platform-independent API to many common system
+features that are implemented differently on every platform. This
+library is intended to be shared among many projects, 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.
+
+You are probably reading this file in the source tree of a surrounding
+project. In that case, see "../README.kwsys" for details of using
+KWSys in your project.
+
+See CONTRIBUTING.rst for instructions to contribute KWSys changes.
diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx
new file mode 100644
index 0000000..22593b4
--- /dev/null
+++ b/Source/kwsys/RegularExpression.cxx
@@ -0,0 +1,1244 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+//
+// 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/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in
new file mode 100644
index 0000000..0bb700f
--- /dev/null
+++ b/Source/kwsys/RegularExpression.hxx.in
@@ -0,0 +1,443 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+// 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/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in
new file mode 100644
index 0000000..f80ef84
--- /dev/null
+++ b/Source/kwsys/SharedForward.h.in
@@ -0,0 +1,944 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 <stddef.h> /* size_t */
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <io.h>
+# include <windows.h>
+# include <process.h>
+# define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */
+#else
+# include <unistd.h>
+# include <sys/stat.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/Source/kwsys/String.c b/Source/kwsys/String.c
new file mode 100644
index 0000000..ed4a6c5
--- /dev/null
+++ b/Source/kwsys/String.c
@@ -0,0 +1,115 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/String.h.in b/Source/kwsys/String.h.in
new file mode 100644
index 0000000..f5bab6e
--- /dev/null
+++ b/Source/kwsys/String.h.in
@@ -0,0 +1,67 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/String.hxx.in b/Source/kwsys/String.hxx.in
new file mode 100644
index 0000000..2e9aedb
--- /dev/null
+++ b/Source/kwsys/String.hxx.in
@@ -0,0 +1,65 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/System.c b/Source/kwsys/System.c
new file mode 100644
index 0000000..ccc7e81
--- /dev/null
+++ b/Source/kwsys/System.c
@@ -0,0 +1,301 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 <stddef.h> /* ptrdiff_t */
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memcpy */
+#include <ctype.h> /* isspace */
+
+#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/Source/kwsys/System.h.in b/Source/kwsys/System.h.in
new file mode 100644
index 0000000..3f3d3f4
--- /dev/null
+++ b/Source/kwsys/System.h.in
@@ -0,0 +1,69 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
new file mode 100644
index 0000000..81fb2f9
--- /dev/null
+++ b/Source/kwsys/SystemInformation.cxx
@@ -0,0 +1,5489 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#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 "SystemInformation.hxx.in"
+# include "Process.h.in"
+#endif
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#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 <sys/time.h>
+# include <sys/utsname.h> // int uname(struct utsname *buf);
+# include <sys/resource.h> // getrlimit
+# include <unistd.h>
+# include <signal.h>
+# include <fcntl.h>
+# include <errno.h> // extern int errno;
+#endif
+
+#if defined (__CYGWIN__) && !defined(_WIN32)
+# include <windows.h>
+# undef _WIN32
+#endif
+
+#ifdef __FreeBSD__
+# include <sys/sysctl.h>
+# include <fenv.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# if defined(KWSYS_SYS_HAS_IFADDRS_H)
+# include <ifaddrs.h>
+# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+# endif
+#endif
+
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+# include <sys/param.h>
+# include <sys/sysctl.h>
+#endif
+
+#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
+# include <machine/cpu.h>
+#endif
+
+#if defined(__DragonFly__)
+# include <sys/sysctl.h>
+#endif
+
+#ifdef __APPLE__
+# include <sys/sysctl.h>
+# include <mach/vm_statistics.h>
+# include <mach/host_info.h>
+# include <mach/mach.h>
+# include <mach/mach_types.h>
+# include <fenv.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# if defined(KWSYS_SYS_HAS_IFADDRS_H)
+# include <ifaddrs.h>
+# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+# endif
+# if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 >= 1050)
+# undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
+# endif
+#endif
+
+#ifdef __linux
+# include <fenv.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# if defined(KWSYS_SYS_HAS_IFADDRS_H)
+# include <ifaddrs.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 <memory.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h> // int isdigit(int c);
+
+#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;
+ bool SupportsHyperthreading;
+ 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;
+
+ int CPUCount(); // For windows
+ unsigned char LogicalCPUPerPhysicalCPU();
+ unsigned char GetAPICId(); // For windows
+ bool IsHyperThreadingSupported();
+ 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;
+};
+
+
+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 = "";
+}
+
+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->CPUCount();
+
+#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;
+ if ((fam==AF_INET) || (fam==AF_INET6))
+ {
+ 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)
+ {
+ this->Features.ExtendedFeatures.SupportsHyperthreading = ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: Hyperthreading --> Bit 28
+ this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (this->Features.ExtendedFeatures.SupportsHyperthreading) ? ((cpuinfo[1] & 0x00FF0000) >> 16) : 1;
+
+ if ((this->Features.ExtendedFeatures.SupportsHyperthreading) && (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 hyperthreading)
+ size_t pos = buffer.find("processor\t");
+ while(pos != buffer.npos)
+ {
+ this->NumberOfLogicalCPU++;
+ pos = buffer.find("processor\t",pos+1);
+ }
+
+#ifdef __linux
+ // Find the largest physical id.
+ int maxId = -1;
+ std::string idc =
+ this->ExtractValueFromCpuInfoFile(buffer,"physical id");
+ while(this->CurrentPositionInFile != buffer.npos)
+ {
+ int id = atoi(idc.c_str());
+ if(id > maxId)
+ {
+ maxId=id;
+ }
+ idc = this->ExtractValueFromCpuInfoFile(buffer,"physical id",
+ this->CurrentPositionInFile+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");
+ int numberOfCoresPerCPU=atoi(cores.c_str());
+ if (maxId > 0)
+ {
+ this->NumberOfPhysicalCPU=static_cast<unsigned int>(
+ numberOfCoresPerCPU*(maxId+1));
+ }
+ else
+ {
+ // Linux Sparc: get cpu count
+ this->NumberOfPhysicalCPU=
+ atoi(this->ExtractValueFromCpuInfoFile(buffer,"ncpus active").c_str());
+ }
+
+#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 => hyperthreading.
+ 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;
+}
+
+/** Return the number of logical CPU per physical CPUs Works only for windows */
+unsigned char SystemInformationImplementation::LogicalCPUPerPhysicalCPU(void)
+{
+#ifdef __APPLE__
+ size_t len = 4;
+ int cores_per_package = 0;
+ int err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len, NULL, 0);
+ if (err != 0)
+ {
+ return 1; // That name was not found, default to 1
+ }
+ return static_cast<unsigned char>(cores_per_package);
+#else
+ int Regs[4] = { 0, 0, 0, 0 };
+#if USE_CPUID
+ if (!this->IsHyperThreadingSupported())
+ {
+ return static_cast<unsigned char>(1); // HT not supported
+ }
+ call_cpuid(1, Regs);
+#endif
+ return static_cast<unsigned char> ((Regs[1] & NUM_LOGICAL_BITS) >> 16);
+#endif
+}
+
+
+/** Works only for windows */
+bool SystemInformationImplementation::IsHyperThreadingSupported()
+{
+ if (this->Features.ExtendedFeatures.SupportsHyperthreading)
+ {
+ return true;
+ }
+
+#if USE_CPUID
+ int Regs[4] = { 0, 0, 0, 0 },
+ VendorId[4] = { 0, 0, 0, 0 };
+ // Get vendor id string
+ if (!call_cpuid(0, VendorId))
+ {
+ return false;
+ }
+ // eax contains family processor type
+ // edx has info about the availability of hyper-Threading
+ if (!call_cpuid(1, Regs))
+ {
+ return false;
+ }
+
+ if (((Regs[0] & FAMILY_ID) == PENTIUM4_ID) || (Regs[0] & EXT_FAMILY_ID))
+ {
+ if (VendorId[1] == 0x756e6547) // 'uneG'
+ {
+ if (VendorId[3] == 0x49656e69) // 'Ieni'
+ {
+ if (VendorId[2] == 0x6c65746e) // 'letn'
+ {
+ // Genuine Intel with hyper-Threading technology
+ this->Features.ExtendedFeatures.SupportsHyperthreading = ((Regs[3] & HT_BIT) != 0);
+ return this->Features.ExtendedFeatures.SupportsHyperthreading;
+ }
+ }
+ }
+ }
+#endif
+
+ return 0; // Not genuine Intel processor
+}
+
+
+/** Return the APIC Id. Works only for windows. */
+unsigned char SystemInformationImplementation::GetAPICId()
+{
+ int Regs[4] = { 0, 0, 0, 0 };
+
+#if USE_CPUID
+ if (!this->IsHyperThreadingSupported())
+ {
+ 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. */
+int SystemInformationImplementation::CPUCount()
+{
+#if defined(_WIN32)
+ unsigned char StatusFlag = 0;
+ SYSTEM_INFO info;
+
+ this->NumberOfPhysicalCPU = 0;
+ this->NumberOfLogicalCPU = 0;
+ info.dwNumberOfProcessors = 0;
+ GetSystemInfo (&info);
+
+ // Number of physical processors in a non-Intel system
+ // or in a 32-bit Intel system with Hyper-Threading technology disabled
+ this->NumberOfPhysicalCPU = (unsigned char) info.dwNumberOfProcessors;
+
+ if (this->IsHyperThreadingSupported())
+ {
+ unsigned char HT_Enabled = 0;
+ this->NumberOfLogicalCPU = this->LogicalCPUPerPhysicalCPU();
+ if (this->NumberOfLogicalCPU >= 1) // >1 Doesn't mean HT is enabled in the BIOS
+ {
+ HANDLE hCurrentProcessHandle;
+#ifndef _WIN64
+# define DWORD_PTR DWORD
+#endif
+ DWORD_PTR dwProcessAffinity;
+ DWORD_PTR dwSystemAffinity;
+ DWORD dwAffinityMask;
+
+ // Calculate the appropriate shifts and mask based on the
+ // number of logical processors.
+ unsigned int i = 1;
+ unsigned char PHY_ID_MASK = 0xFF;
+ //unsigned char PHY_ID_SHIFT = 0;
+
+ while (i < this->NumberOfLogicalCPU)
+ {
+ i *= 2;
+ PHY_ID_MASK <<= 1;
+ // PHY_ID_SHIFT++;
+ }
+
+ hCurrentProcessHandle = GetCurrentProcess();
+ GetProcessAffinityMask(hCurrentProcessHandle, &dwProcessAffinity,
+ &dwSystemAffinity);
+
+ // Check if available process affinity mask is equal to the
+ // available system affinity mask
+ if (dwProcessAffinity != dwSystemAffinity)
+ {
+ StatusFlag = HT_CANNOT_DETECT;
+ this->NumberOfPhysicalCPU = (unsigned char)-1;
+ return StatusFlag;
+ }
+
+ dwAffinityMask = 1;
+ while (dwAffinityMask != 0 && dwAffinityMask <= dwProcessAffinity)
+ {
+ // Check if this CPU is available
+ if (dwAffinityMask & dwProcessAffinity)
+ {
+ if (SetProcessAffinityMask(hCurrentProcessHandle,
+ dwAffinityMask))
+ {
+ unsigned char APIC_ID, LOG_ID;
+ Sleep(0); // Give OS time to switch CPU
+
+ APIC_ID = GetAPICId();
+ LOG_ID = APIC_ID & ~PHY_ID_MASK;
+
+ if (LOG_ID != 0)
+ {
+ HT_Enabled = 1;
+ }
+ }
+ }
+ dwAffinityMask = dwAffinityMask << 1;
+ }
+ // Reset the processor affinity
+ SetProcessAffinityMask(hCurrentProcessHandle, dwProcessAffinity);
+
+ if (this->NumberOfLogicalCPU == 1) // Normal P4 : HT is disabled in hardware
+ {
+ StatusFlag = HT_DISABLED;
+ }
+ else
+ {
+ if (HT_Enabled)
+ {
+ // Total physical processors in a Hyper-Threading enabled system.
+ this->NumberOfPhysicalCPU /= (this->NumberOfLogicalCPU);
+ StatusFlag = HT_ENABLED;
+ }
+ else
+ {
+ StatusFlag = HT_SUPPORTED_NOT_ENABLED;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Processors do not have Hyper-Threading technology
+ StatusFlag = HT_NOT_CAPABLE;
+ this->NumberOfLogicalCPU = 1;
+ }
+ return StatusFlag;
+#else
+ return 0;
+#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);
+ this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical =
+ this->LogicalCPUPerPhysicalCPU();
+
+ 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");
+ if(arch)
+ {
+ this->OSPlatform = arch;
+ }
+
+#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;
+ }
+
+#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 (sizeof(void*) == 8);
+}
+
+
+} // namespace @KWSYS_NAMESPACE@
diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in
new file mode 100644
index 0000000..7c45388
--- /dev/null
+++ b/Source/kwsys/SystemInformation.hxx.in
@@ -0,0 +1,152 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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();
+
+ bool Is64Bits();
+
+ unsigned int GetNumberOfLogicalCPU(); // per physical cpu
+ 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/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
new file mode 100644
index 0000000..f8ea884
--- /dev/null
+++ b/Source/kwsys/SystemTools.cxx
@@ -0,0 +1,5612 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#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 <iostream>
+#include <fstream>
+#include <sstream>
+#include <set>
+#include <vector>
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "RegularExpression.hxx.in"
+# include "SystemTools.hxx.in"
+# include "Directory.hxx.in"
+# include "FStream.hxx.in"
+# include "Encoding.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 <sys/stat.h>
+#include <time.h>
+
+#ifdef _MSC_VER
+# define umask _umask // Note this is still umask on Borland
+#endif
+
+// support for realpath call
+#ifndef _WIN32
+#include <sys/time.h>
+#include <utime.h>
+#include <limits.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <pwd.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 <io.h>
+#include <direct.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::SystemTools::ConvertToWindowsExtendedPath(dir).c_str());
+}
+inline int Rmdir(const std::string& dir)
+{
+ return _wrmdir(
+ KWSYS_NAMESPACE::SystemTools::ConvertToWindowsExtendedPath(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";
+ }
+ const char* cpathEnv = SystemTools::GetEnv(env);
+ if ( !cpathEnv )
+ {
+ return;
+ }
+
+ std::string pathEnv = cpathEnv;
+
+ // 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::GetEnv(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 std::string& key)
+{
+ return SystemTools::GetEnv(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(SystemTools::ConvertToWindowsExtendedPath(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::FileExists(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::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(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str())
+ != INVALID_FILE_ATTRIBUTES);
+#else
+ return access(filename.c_str(), R_OK) == 0;
+#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(
+ SystemTools::ConvertToWindowsExtendedPath(filename).c_str(),
+ permissions) == 0;
+#else
+ return access(filename.c_str(), permissions) == 0;
+#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::FileExists(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(
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(f1).c_str(),
+ GetFileExInfoStandard, &f1d))
+ {
+ return false;
+ }
+ if(!GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(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'))
+ {
+ const char* homeEnv = SystemTools::GetEnv("HOME");
+ if (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
+// Convert local paths to UNC style paths
+std::wstring
+SystemTools::ConvertToWindowsExtendedPath(const std::string &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
+
+// 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(
+ SystemTools::ConvertToWindowsExtendedPath(source).c_str(),
+ GetFileExInfoStandard,
+ &statSource) == 0)
+ {
+ return true;
+ }
+
+ WIN32_FILE_ATTRIBUTE_DATA statDestination;
+ if (GetFileAttributesExW(
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(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 *s1, const char *s2)
+{
+ // lifted from Graphvis http://www.graphviz.org
+ while ((*s1 != '\0')
+ && (tolower(*s1) == tolower(*s2)))
+ {
+ s1++;
+ s2++;
+ }
+
+ return tolower(*s1) - tolower(*s2);
+}
+
+// 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(
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(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 =
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(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(
+ SystemTools::ConvertToWindowsExtendedPath(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
+}
+
+#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].length() == 0)
+ {
+ 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 int GetCasePathName(const std::string & 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 = "";
+ return 0;
+ }
+
+ // 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 = "/";
+ }
+
+ for(; idx < path_components.size(); idx++)
+ {
+ casePath += sep;
+ sep = "/";
+ std::string test_str = casePath;
+ test_str += path_components[idx];
+
+ // 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)
+ {
+ casePath = "";
+ return 0;
+ }
+
+ WIN32_FIND_DATAW findData;
+ HANDLE hFind = ::FindFirstFileW(Encoding::ToWide(test_str).c_str(),
+ &findData);
+ if (INVALID_HANDLE_VALUE != hFind)
+ {
+ casePath += Encoding::ToNarrow(findData.cFileName);
+ ::FindClose(hFind);
+ }
+ else
+ {
+ casePath = "";
+ return 0;
+ }
+ }
+ return (int)casePath.size();
+}
+#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;
+ int len = GetCasePathName(p, casePath);
+ if(len == 0 || len > MAX_PATH+1)
+ {
+ return p;
+ }
+ (*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(const char* userp = getenv("USERPROFILE"))
+ {
+ homedir = userp;
+ }
+ else
+#endif
+ if(const char* h = getenv("HOME"))
+ {
+ homedir = h;
+ }
+ }
+#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);
+ 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-1] = 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;
+ char *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;
+ }
+ columns = getenv("COLUMNS");
+ if(columns && *columns)
+ {
+ long t;
+ char *endptr;
+ t = strtol(columns, &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(
+ SystemTools::ConvertToWindowsExtendedPath(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)
+{
+ // TEMPORARY / TODO: After FileExists calls lstat() instead of
+ // access(), change this call to FileExists instead of
+ // TestFileAccess so that we don't follow symlinks.
+ if ( !SystemTools::TestFileAccess(file, TEST_FILE_OK) )
+ {
+ return false;
+ }
+ if (honor_umask)
+ {
+ mode_t currentMask = umask(0);
+ umask(currentMask);
+ mode &= ~currentMask;
+ }
+#ifdef _WIN32
+ if ( _wchmod(SystemTools::ConvertToWindowsExtendedPath(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.
+ if(const char* pwd = getenv("PWD"))
+ {
+ 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 pwd_str = pwd;
+ std::string cwd_str = cwd;
+ std::string pwd_path;
+ Realpath(pwd, 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 (getenv("DART_TEST_FROM_DART") ||
+ getenv("DASHBOARD_TEST_FROM_CTEST"))
+ {
+ _CrtSetReportHook(SystemToolsDebugReport);
+ }
+}
+
+} // namespace KWSYS_NAMESPACE
+#else
+namespace KWSYS_NAMESPACE
+{
+void SystemTools::EnableMSVCDebugHook() {}
+} // namespace KWSYS_NAMESPACE
+#endif
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
new file mode 100644
index 0000000..8f01e75
--- /dev/null
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -0,0 +1,1005 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_SystemTools_hxx
+#define @KWSYS_NAMESPACE@_SystemTools_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+#include <map>
+
+#include <@KWSYS_NAMESPACE@/String.hxx>
+
+#include <sys/types.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
+ /**
+ * 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 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 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);
+
+ /**
+ * 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 that exists on a windows machine, return the
+ * actuall case of the path as it was created. If the file
+ * does not exist path is returned unchanged. This does nothing
+ * on unix but return 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 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);
+
+
+ /**
+ * 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/Source/kwsys/Terminal.c b/Source/kwsys/Terminal.c
new file mode 100644
index 0000000..a8abb6c
--- /dev/null
+++ b/Source/kwsys/Terminal.c
@@ -0,0 +1,445 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 <stdlib.h> /* getenv */
+#include <string.h> /* strcmp */
+#include <stdarg.h> /* va_list */
+
+#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
+# include <windows.h> /* SetConsoleTextAttribute */
+# include <io.h> /* _get_osfhandle */
+#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",
+ "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/Source/kwsys/Terminal.h.in b/Source/kwsys/Terminal.h.in
new file mode 100644
index 0000000..108cba0
--- /dev/null
+++ b/Source/kwsys/Terminal.h.in
@@ -0,0 +1,159 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/hash_fun.hxx.in b/Source/kwsys/hash_fun.hxx.in
new file mode 100644
index 0000000..4872b51
--- /dev/null
+++ b/Source/kwsys/hash_fun.hxx.in
@@ -0,0 +1,149 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ * 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/Source/kwsys/hash_map.hxx.in b/Source/kwsys/hash_map.hxx.in
new file mode 100644
index 0000000..60c7086
--- /dev/null
+++ b/Source/kwsys/hash_map.hxx.in
@@ -0,0 +1,375 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ * 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/Source/kwsys/hash_set.hxx.in b/Source/kwsys/hash_set.hxx.in
new file mode 100644
index 0000000..c314979
--- /dev/null
+++ b/Source/kwsys/hash_set.hxx.in
@@ -0,0 +1,359 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ * 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/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in
new file mode 100644
index 0000000..9a20226
--- /dev/null
+++ b/Source/kwsys/hashtable.hxx.in
@@ -0,0 +1,997 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ * 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 <stddef.h> // size_t
+#include <algorithm> // lower_bound
+#include <functional> // unary_function
+#include <iterator> // iterator_traits
+#include <memory> // allocator
+#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/Source/kwsys/kwsysHeaderDump.pl b/Source/kwsys/kwsysHeaderDump.pl
new file mode 100755
index 0000000..0dc4a52
--- /dev/null
+++ b/Source/kwsys/kwsysHeaderDump.pl
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+#=============================================================================
+# KWSys - Kitware System Library
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+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/Source/kwsys/kwsysPlatformTests.cmake b/Source/kwsys/kwsysPlatformTests.cmake
new file mode 100644
index 0000000..0da0f63
--- /dev/null
+++ b/Source/kwsys/kwsysPlatformTests.cmake
@@ -0,0 +1,219 @@
+#=============================================================================
+# KWSys - Kitware System Library
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+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/Source/kwsys/kwsysPlatformTestsC.c b/Source/kwsys/kwsysPlatformTestsC.c
new file mode 100644
index 0000000..e602964
--- /dev/null
+++ b/Source/kwsys/kwsysPlatformTestsC.c
@@ -0,0 +1,100 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+/*
+ 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/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx
new file mode 100644
index 0000000..fc87f91
--- /dev/null
+++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx
@@ -0,0 +1,351 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 <sys/stat.h>
+#include <assert.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
diff --git a/Source/kwsys/kwsysPrivate.h b/Source/kwsys/kwsysPrivate.h
new file mode 100644
index 0000000..3a26c26
--- /dev/null
+++ b/Source/kwsys/kwsysPrivate.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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)
+*/
+#define KWSYS_HEADER(x) KWSYS_HEADER0(KWSYS_NAMESPACE/x)
+#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/Source/kwsys/testCommandLineArguments.cxx b/Source/kwsys/testCommandLineArguments.cxx
new file mode 100644
index 0000000..525522d
--- /dev/null
+++ b/Source/kwsys/testCommandLineArguments.cxx
@@ -0,0 +1,187 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/testCommandLineArguments1.cxx b/Source/kwsys/testCommandLineArguments1.cxx
new file mode 100644
index 0000000..6eb465d
--- /dev/null
+++ b/Source/kwsys/testCommandLineArguments1.cxx
@@ -0,0 +1,108 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx
new file mode 100644
index 0000000..7c58769
--- /dev/null
+++ b/Source/kwsys/testDynamicLoader.cxx
@@ -0,0 +1,128 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 <string>
+#include <iostream>
+
+// 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/Source/kwsys/testDynload.c b/Source/kwsys/testDynload.c
new file mode 100644
index 0000000..ba60bec
--- /dev/null
+++ b/Source/kwsys/testDynload.c
@@ -0,0 +1,22 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifdef _WIN32
+#define DL_EXPORT __declspec( dllexport )
+#else
+#define DL_EXPORT
+#endif
+
+DL_EXPORT int TestDynamicLoaderData = 0;
+
+DL_EXPORT void TestDynamicLoaderSymbolPointer()
+{
+}
diff --git a/Source/kwsys/testEncode.c b/Source/kwsys/testEncode.c
new file mode 100644
index 0000000..26d483b
--- /dev/null
+++ b/Source/kwsys/testEncode.c
@@ -0,0 +1,76 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/testEncoding.cxx b/Source/kwsys/testEncoding.cxx
new file mode 100644
index 0000000..80ec040
--- /dev/null
+++ b/Source/kwsys/testEncoding.cxx
@@ -0,0 +1,198 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+
+#if defined(_MSC_VER)
+# pragma warning (disable:4786)
+#endif
+
+#include KWSYS_HEADER(Encoding.hxx)
+#include KWSYS_HEADER(Encoding.h)
+
+#include <iostream>
+#include <locale.h>
+#include <string.h>
+#include <stdlib.h>
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# include "Encoding.hxx.in"
+# include "Encoding.h.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 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;
+}
+
+//----------------------------------------------------------------------------
+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();
+
+ return ret;
+}
diff --git a/Source/kwsys/testFStream.cxx b/Source/kwsys/testFStream.cxx
new file mode 100644
index 0000000..5e53725
--- /dev/null
+++ b/Source/kwsys/testFStream.cxx
@@ -0,0 +1,138 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/testFail.c b/Source/kwsys/testFail.c
new file mode 100644
index 0000000..7e062c1
--- /dev/null
+++ b/Source/kwsys/testFail.c
@@ -0,0 +1,35 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/testHashSTL.cxx b/Source/kwsys/testHashSTL.cxx
new file mode 100644
index 0000000..ae66ceb
--- /dev/null
+++ b/Source/kwsys/testHashSTL.cxx
@@ -0,0 +1,74 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/testIOS.cxx b/Source/kwsys/testIOS.cxx
new file mode 100644
index 0000000..5ff7955
--- /dev/null
+++ b/Source/kwsys/testIOS.cxx
@@ -0,0 +1,164 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Configure.hxx)
+
+#include <sstream>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <string.h> /* strlen */
+
+// 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/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c
new file mode 100644
index 0000000..8fd3382
--- /dev/null
+++ b/Source/kwsys/testProcess.c
@@ -0,0 +1,755 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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 "Process.h.in"
+# include "Encoding.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 <unistd.h>
+# include <signal.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/Source/kwsys/testSharedForward.c.in b/Source/kwsys/testSharedForward.c.in
new file mode 100644
index 0000000..ee753ef
--- /dev/null
+++ b/Source/kwsys/testSharedForward.c.in
@@ -0,0 +1,36 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/testSystemInformation.cxx b/Source/kwsys/testSystemInformation.cxx
new file mode 100644
index 0000000..c96751a
--- /dev/null
+++ b/Source/kwsys/testSystemInformation.cxx
@@ -0,0 +1,119 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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, 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, Is64Bits);
+ 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/Source/kwsys/testSystemTools.bin b/Source/kwsys/testSystemTools.bin
new file mode 100644
index 0000000..961a404
--- /dev/null
+++ b/Source/kwsys/testSystemTools.bin
Binary files differ
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
new file mode 100644
index 0000000..4d97688
--- /dev/null
+++ b/Source/kwsys/testSystemTools.cxx
@@ -0,0 +1,1080 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+
+#if defined(_MSC_VER)
+# pragma warning (disable:4786)
+#endif
+
+#include KWSYS_HEADER(SystemTools.hxx)
+
+// Work-around CMake dependency scanning limitation. This must
+// duplicate the above list of headers.
+#if 0
+# 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;
+ }
+
+ 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;
+ }
+ // 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;
+ }
+ // 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;
+ }
+
+ // 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;
+ }
+
+#ifdef _WIN32
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
+ L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("L:/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
+ L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath
+ ("//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
+ L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("//") !=
+ L"//")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"//\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\") !=
+ L"\\\\.\\")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X") !=
+ L"\\\\.\\X")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X:") !=
+ L"\\\\?\\X:")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X:\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("\\\\.\\X:\\") !=
+ L"\\\\?\\X:\\")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"\\\\.\\X:\\\""
+ << std::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::ConvertToWindowsExtendedPath("NUL") !=
+ L"\\\\.\\NUL")
+ {
+ std::cerr
+ << "Problem with ConvertToWindowsExtendedPath "
+ << "\"NUL\""
+ << std::endl;
+ res = false;
+ }
+
+#endif
+
+ 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;
+ }
+ const char* v = kwsys::SystemTools::GetEnv(name);
+ v = v? v : "(null)";
+ if(strcmp(v, value) != 0)
+ {
+ 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;
+ }
+ if(const char* v = kwsys::SystemTools::GetEnv(name))
+ {
+ 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(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(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;
+}
+
+//----------------------------------------------------------------------------
+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();
+
+ return res ? 0 : 1;
+}
diff --git a/Source/kwsys/testSystemTools.h.in b/Source/kwsys/testSystemTools.h.in
new file mode 100644
index 0000000..66f0f72
--- /dev/null
+++ b/Source/kwsys/testSystemTools.h.in
@@ -0,0 +1,21 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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/Source/kwsys/testTerminal.c b/Source/kwsys/testTerminal.c
new file mode 100644
index 0000000..0d2d7a7
--- /dev/null
+++ b/Source/kwsys/testTerminal.c
@@ -0,0 +1,31 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#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;
+}