From 7d3c2959fa9cb65b3be81bdfe3f69c29d31a9e67 Mon Sep 17 00:00:00 2001 From: KWSys Robot Date: Wed, 2 May 2012 08:46:10 -0400 Subject: [PATCH] KWSys 2012-05-02 (719638e2) Extract upstream KWSys using the following shell code. $ sha1=719638e233b560afb0d9a0afdcf23469dc1827fe && git archive --prefix=KWSys-snapshot/ $sha1 | tar x --- Base64.c | 279 ++ Base64.h.in | 120 + CMakeEmptyInputFile.in | 1 + CMakeLists.txt | 1042 +++++++ CPU.h.in | 117 + CTestConfig.cmake | 18 + CommandLineArguments.cxx | 859 ++++++ CommandLineArguments.hxx.in | 286 ++ Configure.h.in | 145 + Configure.hxx.in | 175 ++ Copyright.txt | 31 + Directory.cxx | 250 ++ Directory.hxx.in | 80 + DynamicLoader.cxx | 482 ++++ DynamicLoader.hxx.in | 101 + EncodeExecutable.c | 114 + ExtraTest.cmake.in | 1 + FundamentalType.h.in | 146 + Glob.cxx | 516 ++++ Glob.hxx.in | 117 + IOStream.cxx | 281 ++ IOStream.hxx.in | 146 + MD5.c | 518 ++++ MD5.h.in | 107 + Process.h.in | 428 +++ ProcessFwd9x.c | 211 ++ ProcessUNIX.c | 2753 +++++++++++++++++++ ProcessWin32.c | 2952 ++++++++++++++++++++ README.txt | 10 + Registry.cxx | 818 ++++++ Registry.hxx.in | 107 + RegularExpression.cxx | 1251 +++++++++ RegularExpression.hxx.in | 414 +++ SharedForward.h.in | 922 +++++++ String.c | 115 + String.h.in | 67 + String.hxx.in | 65 + System.c | 856 ++++++ System.h.in | 162 ++ SystemInformation.cxx | 3675 +++++++++++++++++++++++++ SystemInformation.hxx.in | 88 + SystemTools.cxx | 4860 +++++++++++++++++++++++++++++++++ SystemTools.hxx.in | 904 ++++++ Terminal.c | 432 +++ Terminal.h.in | 159 ++ auto_ptr.hxx.in | 201 ++ hash_fun.hxx.in | 149 + hash_map.hxx.in | 461 ++++ hash_set.hxx.in | 445 +++ hashtable.hxx.in | 1275 +++++++++ kwsysHeaderDump.pl | 50 + kwsysPlatformTests.cmake | 216 ++ kwsysPlatformTestsC.c | 100 + kwsysPlatformTestsCXX.cxx | 516 ++++ kwsysPrivate.h | 41 + kwsys_cstddef.hxx.in | 35 + kwsys_ios_fstream.h.in | 46 + kwsys_ios_iosfwd.h.in | 49 + kwsys_ios_iostream.h.in | 99 + kwsys_ios_sstream.h.in | 199 ++ kwsys_stl.hxx.in | 49 + kwsys_stl_string.hxx.in | 123 + testAutoPtr.cxx | 166 ++ testCommandLineArguments.cxx | 187 ++ testCommandLineArguments1.cxx | 106 + testDynamicLoader.cxx | 133 + testDynload.c | 22 + testEncode.c | 76 + testFail.c | 35 + testHashSTL.cxx | 75 + testIOS.cxx | 167 ++ testProcess.c | 526 ++++ testRegistry.cxx | 109 + testSharedForward.c.in | 36 + testSystemInformation.cxx | 65 + testSystemTools.bin | Bin 0 -> 766 bytes testSystemTools.cxx | 414 +++ testSystemTools.h.in | 20 + testTerminal.c | 31 + 79 files changed, 33403 insertions(+) create mode 100644 Base64.c create mode 100644 Base64.h.in create mode 100644 CMakeEmptyInputFile.in create mode 100644 CMakeLists.txt create mode 100644 CPU.h.in create mode 100644 CTestConfig.cmake create mode 100644 CommandLineArguments.cxx create mode 100644 CommandLineArguments.hxx.in create mode 100644 Configure.h.in create mode 100644 Configure.hxx.in create mode 100644 Copyright.txt create mode 100644 Directory.cxx create mode 100644 Directory.hxx.in create mode 100644 DynamicLoader.cxx create mode 100644 DynamicLoader.hxx.in create mode 100644 EncodeExecutable.c create mode 100644 ExtraTest.cmake.in create mode 100644 FundamentalType.h.in create mode 100644 Glob.cxx create mode 100644 Glob.hxx.in create mode 100644 IOStream.cxx create mode 100644 IOStream.hxx.in create mode 100644 MD5.c create mode 100644 MD5.h.in create mode 100644 Process.h.in create mode 100644 ProcessFwd9x.c create mode 100644 ProcessUNIX.c create mode 100644 ProcessWin32.c create mode 100644 README.txt create mode 100644 Registry.cxx create mode 100644 Registry.hxx.in create mode 100644 RegularExpression.cxx create mode 100644 RegularExpression.hxx.in create mode 100644 SharedForward.h.in create mode 100644 String.c create mode 100644 String.h.in create mode 100644 String.hxx.in create mode 100644 System.c create mode 100644 System.h.in create mode 100644 SystemInformation.cxx create mode 100644 SystemInformation.hxx.in create mode 100644 SystemTools.cxx create mode 100644 SystemTools.hxx.in create mode 100644 Terminal.c create mode 100644 Terminal.h.in create mode 100644 auto_ptr.hxx.in create mode 100644 hash_fun.hxx.in create mode 100644 hash_map.hxx.in create mode 100644 hash_set.hxx.in create mode 100644 hashtable.hxx.in create mode 100755 kwsysHeaderDump.pl create mode 100644 kwsysPlatformTests.cmake create mode 100644 kwsysPlatformTestsC.c create mode 100644 kwsysPlatformTestsCXX.cxx create mode 100644 kwsysPrivate.h create mode 100644 kwsys_cstddef.hxx.in create mode 100644 kwsys_ios_fstream.h.in create mode 100644 kwsys_ios_iosfwd.h.in create mode 100644 kwsys_ios_iostream.h.in create mode 100644 kwsys_ios_sstream.h.in create mode 100644 kwsys_stl.hxx.in create mode 100644 kwsys_stl_string.hxx.in create mode 100644 testAutoPtr.cxx create mode 100644 testCommandLineArguments.cxx create mode 100644 testCommandLineArguments1.cxx create mode 100644 testDynamicLoader.cxx create mode 100644 testDynload.c create mode 100644 testEncode.c create mode 100644 testFail.c create mode 100644 testHashSTL.cxx create mode 100644 testIOS.cxx create mode 100644 testProcess.c create mode 100644 testRegistry.cxx create mode 100644 testSharedForward.c.in create mode 100644 testSystemInformation.cxx create mode 100644 testSystemTools.bin create mode 100644 testSystemTools.cxx create mode 100644 testSystemTools.h.in create mode 100644 testTerminal.c diff --git a/Base64.c b/Base64.c new file mode 100644 index 000000000..d07bdd01b --- /dev/null +++ b/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). */ +unsigned long kwsysBase64_Encode(const unsigned char *input, + unsigned long 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 (unsigned long)(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). */ +unsigned long kwsysBase64_Decode(const unsigned char *input, + unsigned long length, + unsigned char *output, + unsigned long 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 (unsigned long)(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 (unsigned long)(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 (unsigned long)(optr - output); +} diff --git a/Base64.h.in b/Base64.h.in new file mode 100644 index 000000000..346800768 --- /dev/null +++ b/Base64.h.in @@ -0,0 +1,120 @@ +/*============================================================================ + 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> + +/* 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 unsigned long kwsysBase64_Encode(const unsigned char *input, + unsigned long 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 unsigned long kwsysBase64_Decode(const unsigned char *input, + unsigned long length, + unsigned char *output, + unsigned long 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/CMakeEmptyInputFile.in b/CMakeEmptyInputFile.in new file mode 100644 index 000000000..40b7ea245 --- /dev/null +++ b/CMakeEmptyInputFile.in @@ -0,0 +1 @@ +@CMAKE_EMPTY_INPUT_FILE_CONTENT@ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..a132357f3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,1042 @@ +#============================================================================= +# 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}) +# +# KWSYS_IOS_FORCE_OLD = Force use of old non-ANSI C++ streams even if +# new streams are available. This may be used +# by projects that cannot configure their +# streams library. +# Example: +# +# SET(KWSYS_IOS_FORCE_OLD 1) +# +# +# 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 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 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(NOT KWSYS_NAMESPACE) + +#----------------------------------------------------------------------------- +# 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_Glob 1) + SET(KWSYS_USE_MD5 1) + SET(KWSYS_USE_Process 1) + SET(KWSYS_USE_RegularExpression 1) + SET(KWSYS_USE_Registry 1) + SET(KWSYS_USE_System 1) + SET(KWSYS_USE_SystemTools 1) + SET(KWSYS_USE_CommandLineArguments 1) + SET(KWSYS_USE_FundamentalType 1) + SET(KWSYS_USE_Terminal 1) + SET(KWSYS_USE_IOStream 1) + SET(KWSYS_USE_String 1) + SET(KWSYS_USE_SystemInformation 1) + SET(KWSYS_USE_CPU 1) +ENDIF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) + +# Enforce component dependencies. +IF(KWSYS_USE_SystemTools) + SET(KWSYS_USE_Directory 1) +ENDIF(KWSYS_USE_SystemTools) +IF(KWSYS_USE_Glob) + SET(KWSYS_USE_Directory 1) + SET(KWSYS_USE_SystemTools 1) + SET(KWSYS_USE_RegularExpression 1) +ENDIF(KWSYS_USE_Glob) +IF(KWSYS_USE_Process) + SET(KWSYS_USE_System 1) +ENDIF(KWSYS_USE_Process) +IF(KWSYS_USE_SystemInformation) + SET(KWSYS_USE_Process 1) +ENDIF(KWSYS_USE_SystemInformation) + +# Setup the large file support default. +IF(KWSYS_LFS_DISABLE) + SET(KWSYS_LFS_REQUESTED 0) +ELSE(KWSYS_LFS_DISABLE) + SET(KWSYS_LFS_REQUESTED 1) +ENDIF(KWSYS_LFS_DISABLE) + +# 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(BUILD_TESTING) +ENDIF(KWSYS_STANDALONE) + +# 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(NOT KWSYS_INSTALL_INCLUDE_DIR) +IF(NOT KWSYS_INSTALL_LIB_DIR) + STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR + "${KWSYS_LIBRARY_INSTALL_DIR}") +ENDIF(NOT KWSYS_INSTALL_LIB_DIR) +IF(NOT KWSYS_INSTALL_BIN_DIR) + STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR + "${KWSYS_LIBRARY_INSTALL_DIR}") +ENDIF(NOT KWSYS_INSTALL_BIN_DIR) + +# 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(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) + +# 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(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) + + # 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(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) +ENDIF(KWSYS_INSTALL_LIB_DIR) +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(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) +ENDIF(KWSYS_INSTALL_BIN_DIR) + +# 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 COPY_ONLY IMMEDIATE) +ENDIF(NOT KWSYS_IN_SOURCE_BUILD) + +# 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(CMAKE_ANSI_CFLAGS) + +#----------------------------------------------------------------------------- +# 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(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL) + IF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include") + ENDIF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE) + ENDIF(CMAKE_SYSTEM MATCHES "OSF1-V.*") + IF(CMAKE_SYSTEM MATCHES "HP-UX") + SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p") + ENDIF(CMAKE_SYSTEM MATCHES "HP-UX") +ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX) + +#----------------------------------------------------------------------------- +# 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(KWSYS_LFS_WORKS) +ELSE(KWSYS_LFS_REQUESTED) + # Large File Support is not requested. + SET(KWSYS_LFS_REQUESTED 0) +ENDIF(KWSYS_LFS_REQUESTED) + +#----------------------------------------------------------------------------- +# 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. + +KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAVE_STD + "Checking whether STL classes are in std namespace" DIRECT) + +IF(KWSYS_IOS_FORCE_OLD) + SET(KWSYS_IOS_USE_ANSI 0) +ELSE(KWSYS_IOS_FORCE_OLD) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_USE_ANSI + "Checking whether ANSI stream headers are available" DIRECT) +ENDIF(KWSYS_IOS_FORCE_OLD) + +IF(KWSYS_IOS_USE_ANSI) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAVE_STD + "Checking whether ANSI streams are in std namespace" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_USE_SSTREAM + "Checking whether ANSI string stream is available" DIRECT) +ELSE(KWSYS_IOS_USE_ANSI) + SET(KWSYS_IOS_HAVE_STD 0) + SET(KWSYS_IOS_USE_SSTREAM 0) +ENDIF(KWSYS_IOS_USE_ANSI) + +IF(KWSYS_IOS_USE_SSTREAM) + SET(KWSYS_IOS_USE_STRSTREAM_H 0) + SET(KWSYS_IOS_USE_STRSTREA_H 0) +ELSE(KWSYS_IOS_USE_SSTREAM) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_USE_STRSTREAM_H + "Checking whether strstream.h is available" DIRECT) + IF(KWSYS_IOS_USE_STRSTREAM_H) + SET(KWSYS_IOS_USE_STRSTREA_H 0) + ELSE(KWSYS_IOS_USE_STRSTREAM_H) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_USE_STRSTREA_H + "Checking whether strstrea.h is available" DIRECT) + ENDIF(KWSYS_IOS_USE_STRSTREAM_H) +ENDIF(KWSYS_IOS_USE_SSTREAM) + +KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CSTDDEF + "Checking whether header cstddef is available" DIRECT) + +SET(KWSYS_PLATFORM_CXX_TEST_DEFINES + -DKWSYS_STL_HAVE_STD=${KWSYS_STL_HAVE_STD}) +KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_STRING_HAVE_NEQ_CHAR + "Checking whether stl string has operator!= for char*" DIRECT) +KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_ITERATOR_TRAITS + "Checking whether stl has iterator_traits" DIRECT) +IF(KWSYS_STL_HAS_ITERATOR_TRAITS) + SET(KWSYS_STL_HAS_ITERATOR_CATEGORY 0) + SET(KWSYS_STL_HAS___ITERATOR_CATEGORY 0) +ELSE(KWSYS_STL_HAS_ITERATOR_TRAITS) + KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_ITERATOR_CATEGORY + "Checking whether stl has old iterator_category" DIRECT) + IF(KWSYS_STL_HAS_ITERATOR_CATEGORY) + SET(KWSYS_STL_HAS___ITERATOR_CATEGORY 0) + ELSE(KWSYS_STL_HAS_ITERATOR_CATEGORY) + KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS___ITERATOR_CATEGORY + "Checking whether stl has internal __iterator_category" DIRECT) + ENDIF(KWSYS_STL_HAS_ITERATOR_CATEGORY) +ENDIF(KWSYS_STL_HAS_ITERATOR_TRAITS) +KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_ALLOCATOR_TEMPLATE + "Checking whether stl has standard template allocator" DIRECT) +IF(KWSYS_STL_HAS_ALLOCATOR_TEMPLATE) + SET(KWSYS_STL_HAS_ALLOCATOR_NONTEMPLATE 0) + KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_ALLOCATOR_REBIND + "Checking for rebind member of stl allocator" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_ALLOCATOR_MAX_SIZE_ARGUMENT + "Checking for non-standard argument to stl allocator<>::max_size" DIRECT) +ELSE(KWSYS_STL_HAS_ALLOCATOR_TEMPLATE) + KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_ALLOCATOR_NONTEMPLATE + "Checking whether stl has old non-template allocator" DIRECT) + SET(KWSYS_STL_HAS_ALLOCATOR_REBIND 0) + SET(KWSYS_STL_HAS_ALLOCATOR_MAX_SIZE_ARGUMENT 0) +ENDIF(KWSYS_STL_HAS_ALLOCATOR_TEMPLATE) +KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_ALLOCATOR_OBJECTS + "Checking whether stl containers support allocator objects." DIRECT) +IF(KWSYS_IOS_USE_ANSI AND NOT WATCOM) + # ANSI streams always have string operators. + SET(KWSYS_STL_STRING_HAVE_OSTREAM 1) + SET(KWSYS_STL_STRING_HAVE_ISTREAM 1) +ELSE(KWSYS_IOS_USE_ANSI AND NOT WATCOM) + # There may not be string operators for old streams. + KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_STRING_HAVE_OSTREAM + "Checking whether stl string has ostream operator<<" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_STRING_HAVE_ISTREAM + "Checking whether stl string has istream operator>>" DIRECT) +ENDIF(KWSYS_IOS_USE_ANSI AND NOT WATCOM) +SET(KWSYS_PLATFORM_CXX_TEST_DEFINES + -DKWSYS_IOS_USE_ANSI=${KWSYS_IOS_USE_ANSI} + -DKWSYS_IOS_HAVE_STD=${KWSYS_IOS_HAVE_STD}) +KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAVE_BINARY + "Checking whether ios has binary openmode" DIRECT) +SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) + +KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_NULL_TEMPLATE_ARGS + "Checking whether \"<>\" is needed for template friends" INVERT) +KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_MEMBER_TEMPLATES + "Checking for member template support" DIRECT) +KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_FULL_SPECIALIZATION + "Checking for standard template specialization syntax" DIRECT) +KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ARGUMENT_DEPENDENT_LOOKUP + "Checking whether argument dependent lookup is supported" DIRECT) + +IF(UNIX) + KWSYS_PLATFORM_CXX_TEST(KWSYS_STAT_HAS_ST_MTIM + "Checking whether struct stat has st_mtim member" DIRECT) +ENDIF(UNIX) + +# 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_FundamentalType) + # Look for type size helper macros. + KWSYS_PLATFORM_INFO_TEST(C KWSYS_C_TYPE_MACROS + "Checking for C type size macros") + SET(macro_regex ".*INFO:macro\\[([^]]*)\\].*") + FOREACH(info ${KWSYS_C_TYPE_MACROS}) + IF("${info}" MATCHES "${macro_regex}") + STRING(REGEX REPLACE "${macro_regex}" "\\1" macro "${info}") + SET(KWSYS_C_HAS_MACRO_${macro} 1) + ENDIF() + ENDFOREACH() + + # Determine type sizes at preprocessing time if possible, and + # otherwise fall back to a try-compile. + SET(KWSYS_C_TYPE_NAME_CHAR "char") + SET(KWSYS_C_TYPE_NAME_SHORT "short") + SET(KWSYS_C_TYPE_NAME_INT "int") + SET(KWSYS_C_TYPE_NAME_LONG "long") + SET(KWSYS_C_TYPE_NAME_LONG_LONG "long long") + SET(KWSYS_C_TYPE_NAME___INT64 "__int64") + FOREACH(type CHAR SHORT INT LONG LONG_LONG __INT64) + IF(KWSYS_C_HAS_MACRO___SIZEOF_${type}__) + # Use __SIZEOF_${type}__ macro. + SET(KWSYS_SIZEOF_${type} TRUE) + SET(KWSYS_C_CODE_SIZEOF_${type} "#define ${KWSYS_NAMESPACE}_SIZEOF_${type} __SIZEOF_${type}__") + ELSEIF(KWSYS_C_HAS_MACRO___${type}_MAX__) + # Use __${type}_MAX__ macro. + SET(KWSYS_SIZEOF_${type} TRUE) + SET(KWSYS_C_CODE_SIZEOF_${type} "#if __${type}_MAX__ == 0x7f +# define ${KWSYS_NAMESPACE}_SIZEOF_${type} 1 +#elif __${type}_MAX__ == 0x7fff +# define ${KWSYS_NAMESPACE}_SIZEOF_${type} 2 +#elif __${type}_MAX__ == 0x7fffffff +# define ${KWSYS_NAMESPACE}_SIZEOF_${type} 4 +#elif __${type}_MAX__>>32 == 0x7fffffff +# define ${KWSYS_NAMESPACE}_SIZEOF_${type} 8 +#else +# error \"Cannot determine sizeof(${KWSYS_C_TYPE_NAME_${type}}).\" +#endif") + ELSE() + # Configure a hard-coded type size. + CHECK_TYPE_SIZE("${KWSYS_C_TYPE_NAME_${type}}" KWSYS_SIZEOF_${type}) + IF(NOT KWSYS_SIZEOF_${type}) + SET(KWSYS_SIZEOF_${type} 0) + ENDIF() + SET(KWSYS_C_CODE_SIZEOF_${type} + "#define ${KWSYS_NAMESPACE}_SIZEOF_${type} ${KWSYS_SIZEOF_${type}}") + ENDIF() + ENDFOREACH() + + IF(KWSYS_USE___INT64) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CAN_CONVERT_UI64_TO_DOUBLE + "Checking whether unsigned __int64 can convert to double" DIRECT) + ELSE(KWSYS_USE___INT64) + SET(KWSYS_CAN_CONVERT_UI64_TO_DOUBLE 1) + ENDIF(KWSYS_USE___INT64) + + # Check signedness of "char" type. + KWSYS_PLATFORM_CXX_TEST_RUN(KWSYS_CHAR_IS_SIGNED + "Checking whether char is signed" DIRECT) +ENDIF(KWSYS_USE_FundamentalType) + +IF(KWSYS_USE_IOStream) + # Determine whether iostreams support long long. + IF(KWSYS_CXX_HAS_LONG_LONG) + SET(KWSYS_PLATFORM_CXX_TEST_DEFINES + -DKWSYS_IOS_USE_ANSI=${KWSYS_IOS_USE_ANSI} + -DKWSYS_IOS_HAVE_STD=${KWSYS_IOS_HAVE_STD}) + 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) + SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) + ELSE() + SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0) + SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0) + ENDIF() +ENDIF(KWSYS_USE_IOStream) + +IF(KWSYS_NAMESPACE MATCHES "^kwsys$") + SET(KWSYS_NAME_IS_KWSYS 1) +ELSE(KWSYS_NAMESPACE MATCHES "^kwsys$") + SET(KWSYS_NAME_IS_KWSYS 0) +ENDIF(KWSYS_NAMESPACE MATCHES "^kwsys$") + +# Choose default shared/static build if not specified. +IF(KWSYS_BUILD_SHARED MATCHES "^KWSYS_BUILD_SHARED$") + SET(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS}) +ENDIF(KWSYS_BUILD_SHARED MATCHES "^KWSYS_BUILD_SHARED$") + +IF(KWSYS_BUILD_SHARED) + SET(KWSYS_BUILD_SHARED 1) + SET(KWSYS_LIBRARY_TYPE SHARED) +ELSE(KWSYS_BUILD_SHARED) + SET(KWSYS_BUILD_SHARED 0) + SET(KWSYS_LIBRARY_TYPE STATIC) +ENDIF(KWSYS_BUILD_SHARED) + +#----------------------------------------------------------------------------- +# 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) + SET_SOURCE_FILES_PROPERTIES(SystemTools.cxx PROPERTIES + COMPILE_FLAGS "-DKWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} -DKWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV} -DKWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H}") +ENDIF() + +IF(KWSYS_USE_SystemInformation) + SET_PROPERTY(SOURCE SystemInformation.cxx PROPERTY + COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=${KWSYS_USE_LONG_LONG} + KWSYS_USE___INT64=${KWSYS_USE___INT64}) +ENDIF() + +#----------------------------------------------------------------------------- +# Choose a directory for the generated headers. +IF(NOT KWSYS_HEADER_ROOT) + SET(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}") +ENDIF(NOT KWSYS_HEADER_ROOT) +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(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) + + # 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(KWSYS_INSTALL_DOC_DIR) + +#----------------------------------------------------------------------------- +# Create STL header wrappers to block warnings in the STL headers and +# give standard names by which they may be included. +SET(KWSYS_STL_HEADER_EXTRA_string 1) +FOREACH(header + algorithm + deque + exception + functional + iterator + list + map + memory + new + numeric + queue + set + stack + stdexcept + string + utility + vector + ) + # Configure the header wrapper. + SET(KWSYS_STL_HEADER "${header}") + IF(KWSYS_STL_HEADER_EXTRA_${header}) + SET(KWSYS_STL_HEADER_EXTRA + "#define ${KWSYS_NAMESPACE}_stl_${header}_including_hxx\n# include <${KWSYS_NAMESPACE}/stl/${header}.hxx>\n#undef ${KWSYS_NAMESPACE}_stl_${header}_including_hxx\n") + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsys_stl_${header}.hxx.in + ${KWSYS_HEADER_DIR}/stl/${header}.hxx + @ONLY IMMEDIATE) + IF(KWSYS_INSTALL_INCLUDE_DIR) + INSTALL(FILES ${KWSYS_HEADER_DIR}/stl/${header}.hxx + DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}/stl + ${KWSYS_INSTALL_INCLUDE_OPTIONS}) + ENDIF(KWSYS_INSTALL_INCLUDE_DIR) + ELSE(KWSYS_STL_HEADER_EXTRA_${header}) + SET(KWSYS_STL_HEADER_EXTRA "") + ENDIF(KWSYS_STL_HEADER_EXTRA_${header}) + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsys_stl.hxx.in + ${KWSYS_HEADER_DIR}/stl/${header} + @ONLY IMMEDIATE) + + # Create an install target for the header wrapper. + IF(KWSYS_INSTALL_INCLUDE_DIR) + INSTALL(FILES ${KWSYS_HEADER_DIR}/stl/${header} + DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}/stl + ${KWSYS_INSTALL_INCLUDE_OPTIONS}) + ENDIF(KWSYS_INSTALL_INCLUDE_DIR) +ENDFOREACH(header) + +# Provide cstddef header. +CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsys_cstddef.hxx.in + ${KWSYS_HEADER_DIR}/cstddef + @ONLY IMMEDIATE) +IF(KWSYS_INSTALL_INCLUDE_DIR) + INSTALL(FILES ${KWSYS_HEADER_DIR}/cstddef + DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} + ${KWSYS_INSTALL_INCLUDE_OPTIONS}) +ENDIF(KWSYS_INSTALL_INCLUDE_DIR) + +#----------------------------------------------------------------------------- +# Create streams header wrappers to give standard names by which they +# may be included. +FOREACH(header iostream fstream sstream iosfwd) + # Configure the header wrapper. + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsys_ios_${header}.h.in + ${KWSYS_HEADER_DIR}/ios/${header} + @ONLY IMMEDIATE) + + # Create an install target for the header wrapper. + IF(KWSYS_INSTALL_INCLUDE_DIR) + INSTALL(FILES ${KWSYS_HEADER_DIR}/ios/${header} + DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}/ios + ${KWSYS_INSTALL_INCLUDE_OPTIONS}) + ENDIF(KWSYS_INSTALL_INCLUDE_DIR) +ENDFOREACH(header) + +#----------------------------------------------------------------------------- +# 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 + auto_ptr + ) + +# Add selected C++ classes. +SET(cppclasses + Directory DynamicLoader Glob RegularExpression SystemTools + CommandLineArguments Registry IOStream 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(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) + ENDIF(KWSYS_USE_${cpp}) +ENDFOREACH(cpp) + +# Add selected C components. +FOREACH(c + Process Base64 FundamentalType MD5 Terminal System String CPU + ) + 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(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) + ENDIF(KWSYS_USE_${c}) +ENDFOREACH(c) + +#----------------------------------------------------------------------------- +# 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. We need the encoded forwarding executable. + SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c + ${PROJECT_BINARY_DIR}/${KWSYS_NAMESPACE}ProcessFwd9xEnc.c) + SET_SOURCE_FILES_PROPERTIES( + ${PROJECT_BINARY_DIR}/${KWSYS_NAMESPACE}ProcessFwd9xEnc.c + PROPERTIES GENERATED 1) + ELSE(NOT UNIX) + # Use the UNIX implementation. + SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c) + ENDIF(NOT UNIX) +ENDIF(KWSYS_USE_Process) + +# Add selected C sources. +FOREACH(c Base64 MD5 Terminal System String) + IF(KWSYS_USE_${c}) + SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${c}.c) + ENDIF(KWSYS_USE_${c}) +ENDFOREACH(c) + +# 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. + SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${c}.cxx) + + # 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(KWSYS_INSTALL_INCLUDE_DIR) +ENDFOREACH(c) + +# 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(KWSYS_INSTALL_INCLUDE_DIR) +ENDFOREACH(h) + +# 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(KWSYS_INSTALL_INCLUDE_DIR) +ENDFOREACH(h) + +#----------------------------------------------------------------------------- +# 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(UNIX) + ENDIF(KWSYS_USE_DynamicLoader) + + IF(KWSYS_USE_SystemInformation AND WIN32) + TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ws2_32) + ENDIF(KWSYS_USE_SystemInformation AND WIN32) + + # Apply user-defined target properties to the library. + IF(KWSYS_PROPERTIES_CXX) + SET_TARGET_PROPERTIES(${KWSYS_NAMESPACE} PROPERTIES + ${KWSYS_PROPERTIES_CXX} + ) + ENDIF(KWSYS_PROPERTIES_CXX) + + # Create an install target for the library. + IF(KWSYS_INSTALL_LIBRARY_RULE) + INSTALL(TARGETS ${KWSYS_NAMESPACE} ${KWSYS_INSTALL_LIBRARY_RULE}) + ENDIF(KWSYS_INSTALL_LIBRARY_RULE) +ENDIF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) + +# 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} PROPERTIES + ${KWSYS_PROPERTIES_C} + ) + ENDIF(KWSYS_PROPERTIES_C) + + # Create an install target for the library. + IF(KWSYS_INSTALL_LIBRARY_RULE) + INSTALL(TARGETS ${KWSYS_NAMESPACE}_c ${KWSYS_INSTALL_LIBRARY_RULE}) + ENDIF(KWSYS_INSTALL_LIBRARY_RULE) +ENDIF(KWSYS_ENABLE_C AND KWSYS_C_SRCS) + +# 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}") + +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(KWSYS_USE_String) + +#----------------------------------------------------------------------------- +# Process execution on windows needs to build a forwarding executable +# that works around a Win9x bug. We encode the executable into a C +# file and build it into the library. Win9x platforms reproduce the +# executable into a temporary directory when it is needed. +IF(KWSYS_USE_Process) + IF(NOT UNIX) + # Build the forwarding executable itself and a program that will + # encode it into a C file. + ADD_EXECUTABLE(${KWSYS_NAMESPACE}ProcessFwd9x ProcessFwd9x.c) + ADD_EXECUTABLE(${KWSYS_NAMESPACE}EncodeExecutable EncodeExecutable.c) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}ProcessFwd9x PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}EncodeExecutable PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}ProcessFwd9x PROPERTY LABELS ${KWSYS_LABELS_EXE}) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}EncodeExecutable PROPERTY LABELS ${KWSYS_LABELS_EXE}) + + SET(CFG_INTDIR "/${CMAKE_CFG_INTDIR}") + IF(CMAKE_BUILD_TOOL MATCHES "make") + SET(CFG_INTDIR "") + ENDIF(CMAKE_BUILD_TOOL MATCHES "make") + + # Take advantage of a better custom command syntax if possible. + SET(CMD ${CMAKE_CURRENT_BINARY_DIR}${CFG_INTDIR}/${KWSYS_NAMESPACE}EncodeExecutable.exe) + SET(FWD ${CMAKE_CURRENT_BINARY_DIR}${CFG_INTDIR}/${KWSYS_NAMESPACE}ProcessFwd9x.exe) + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${KWSYS_NAMESPACE}ProcessFwd9xEnc.c + COMMAND ${CMD} + ARGS ${FWD} ${CMAKE_CURRENT_BINARY_DIR}/${KWSYS_NAMESPACE}ProcessFwd9xEnc.c + ${KWSYS_NAMESPACE} ProcessFwd9x + DEPENDS ${CMD} ${FWD}) + + # Make sure build occurs in proper order. + ADD_DEPENDENCIES(${KWSYS_NAMESPACE} ${KWSYS_NAMESPACE}ProcessFwd9x + ${KWSYS_NAMESPACE}EncodeExecutable) + ENDIF(NOT UNIX) +ENDIF(KWSYS_USE_Process) + +#----------------------------------------------------------------------------- +# 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(EXECUTABLE_OUTPUT_PATH) + + # 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(test) + + # C++ tests + IF(NOT WATCOM) + SET(KWSYS_CXX_TESTS + testAutoPtr + testHashSTL + ) + ENDIF(NOT WATCOM) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testRegistry + testIOS + testSystemTools + testCommandLineArguments + testCommandLineArguments1 + ) + IF(KWSYS_USE_SystemInformation) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation) + ENDIF(KWSYS_USE_SystemInformation) + 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(KWSYS_USE_DynamicLoader) + 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_BIN_FILE + "${CMAKE_CURRENT_SOURCE_DIR}/testSystemTools.bin") + SET(TEST_SYSTEMTOOLS_SRC_FILE + "${CMAKE_CURRENT_SOURCE_DIR}/testSystemTools.cxx") + 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(CTEST_TEST_KWSYS) + + 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(test) + + # 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(NOT CYGWIN) + FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7}) + 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(n) + + # 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) + 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.testRegistry PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR_NOT_VALGRIND;FAIL;Test failed") + SET_TESTS_PROPERTIES(kwsys.testRegistry PROPERTIES PASS_REGULAR_EXPRESSION "Test passed") + SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value") + MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}") + ENDIF() + + # 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(BUILD_TESTING) +ENDIF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) diff --git a/CPU.h.in b/CPU.h.in new file mode 100644 index 000000000..ecd29d133 --- /dev/null +++ b/CPU.h.in @@ -0,0 +1,117 @@ +/*============================================================================ + 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@_CPU_h +#define @KWSYS_NAMESPACE@_CPU_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +/* Identify possible endian cases. The macro + @KWSYS_NAMESPACE@_CPU_ENDIAN_ID will be defined to one of these, or + 0 if unknown. */ +#define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG 4321 +#define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE 1234 + +/* Apple always defines one of these. */ +#if defined(__LITTLE_ENDIAN__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE +#elif defined(__BIG_ENDIAN__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* Alpha */ +#elif defined(__alpha) || defined(__alpha__) || defined(_M_ALPHA) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE + +/* Arm */ +#elif defined(__arm__) +# if !defined(__ARMEB__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE +# else +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG +# endif + +/* Intel x86 */ +#elif defined(__i386) || defined(__i386__) || defined(_M_IX86) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE +#elif defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE +#elif defined(__MWERKS__) && defined(__INTEL__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE + +/* Intel x86-64 */ +#elif defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE +#elif defined(__amd64) || defined(__amd64__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE + +/* Intel Architecture-64 (Itanium) */ +#elif defined(__ia64) || defined(__ia64__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE +#elif defined(_IA64) || defined(__IA64__) || defined(_M_IA64) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE + +/* PowerPC */ +#elif defined(__powerpc) || defined(__powerpc__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG +#elif defined(__ppc) || defined(__ppc__) || defined(__POWERPC__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* SPARC */ +#elif defined(__sparc) || defined(__sparc__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* HP/PA RISC */ +#elif defined(__hppa) || defined(__hppa__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* Motorola 68k */ +#elif defined(__m68k__) || defined(M68000) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* MIPS */ +#elif defined(__mips) || defined(__mips__) || defined(__MIPS__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* RS/6000 */ +#elif defined(__THW_RS600) || defined(_IBMR2) || defined(_POWER) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG +#elif defined(_ARCH_PWR) || defined(_ARCH_PWR2) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* System/370 */ +#elif defined(__370__) || defined(__THW_370__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* System/390 */ +#elif defined(__s390__) || defined(__s390x__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* z/Architecture */ +#elif defined(__SYSC_ZARCH__) +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG + +/* Unknown CPU */ +#else +# define @KWSYS_NAMESPACE@_CPU_ENDIAN_ID 0 +# if !defined(@KWSYS_NAMESPACE@_CPU_UNKNOWN_OKAY) +# error "The target CPU architecture is not known." +# endif +#endif + +/* If building a C or C++ file in kwsys itself, give the source file + access to the macros without a configured namespace. */ +#if defined(KWSYS_NAMESPACE) +# define KWSYS_CPU_ENDIAN_ID @KWSYS_NAMESPACE@_CPU_ENDIAN_ID +# define KWSYS_CPU_ENDIAN_ID_BIG @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_BIG +# define KWSYS_CPU_ENDIAN_ID_LITTLE @KWSYS_NAMESPACE@_CPU_ENDIAN_ID_LITTLE +#endif + +#endif diff --git a/CTestConfig.cmake b/CTestConfig.cmake new file mode 100644 index 000000000..9ab6ed86c --- /dev/null +++ b/CTestConfig.cmake @@ -0,0 +1,18 @@ +#============================================================================= +# 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 (CTEST_PROJECT_NAME "kwsys") +set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT") +set (CTEST_DART_SERVER_VERSION "2") +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "www.cdash.org") +set(CTEST_DROP_LOCATION "/CDash/submit.php?project=PublicDashboard") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/CommandLineArguments.cxx b/CommandLineArguments.cxx new file mode 100644 index 000000000..ece88ae89 --- /dev/null +++ b/CommandLineArguments.cxx @@ -0,0 +1,859 @@ +/*============================================================================ + 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) + +#include KWSYS_HEADER(stl/vector) +#include KWSYS_HEADER(stl/map) +#include KWSYS_HEADER(stl/set) +#include KWSYS_HEADER(ios/sstream) +#include KWSYS_HEADER(ios/iostream) + +// 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 "kwsys_stl.hxx.in" +# include "kwsys_ios_sstream.h.in" +# include "kwsys_ios_iostream.h.in" +#endif + +#include +#include +#include + +#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) \ + kwsys_ios::cout << __LINE__ << " CLA: " << x << kwsys_ios::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 kwsys_stl::vector {}; +class CommandLineArgumentsSetOfStrings : + public kwsys_stl::set {}; +class CommandLineArgumentsMapOfStrucs : + public kwsys_stl::map {}; + +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(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( + kwsys_stl::vector* matches, + const kwsys_stl::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->size() > 0; +} + +//---------------------------------------------------------------------------- +int CommandLineArguments::Parse() +{ + kwsys_stl::vector::size_type cc; + kwsys_stl::vector matches; + if ( this->StoreUnusedArgumentsFlag ) + { + this->Internals->UnusedArguments.clear(); + } + for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ ) + { + const kwsys_stl::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 kwsys_stl::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].c_str()); + // 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.c_str() + 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 kwsys_stl::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: + kwsys_ios::cerr << "Got unknown argument type: \"" << cs->ArgumentType << "\"" << kwsys_ios::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.c_str()); + } + else + { + kwsys_ios::cerr << "Got unknown argument: \"" << arg.c_str() << "\"" << kwsys_ios::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, kwsys_stl::string) + +CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL, kwsys_stl::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_INT, kwsys_stl::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, kwsys_stl::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, kwsys_stl::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING, kwsys_stl::vector) + +//---------------------------------------------------------------------------- +#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, kwsys_stl::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(this->Internals->LastArgument + 1); +} + +//---------------------------------------------------------------------------- +void CommandLineArguments::GenerateHelp() +{ + kwsys_ios::ostringstream str; + + // Collapse all arguments into the map of vectors of all arguments that do + // the same thing. + CommandLineArguments::Internal::CallbacksMap::iterator it; + typedef kwsys_stl::map 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(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 << kwsys_ios::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(skip)); + str << kwsys_ios::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 kwsys_stl::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 kwsys_stl::string& value) +{ + char* res = 0; + *variable = static_cast(strtol(value.c_str(), &res, 10)); + //if ( res && *res ) + // { + // Can handle non-int + // } +} + +//---------------------------------------------------------------------------- +void CommandLineArguments::PopulateVariable( + double* variable, const kwsys_stl::string& value) +{ + char* res = 0; + *variable = strtod(value.c_str(), &res); + //if ( res && *res ) + // { + // Can handle non-double + // } +} + +//---------------------------------------------------------------------------- +void CommandLineArguments::PopulateVariable( + char** variable, const kwsys_stl::string& value) +{ + if ( *variable ) + { + delete [] *variable; + *variable = 0; + } + *variable = new char[ value.size() + 1 ]; + strcpy(*variable, value.c_str()); +} + +//---------------------------------------------------------------------------- +void CommandLineArguments::PopulateVariable( + kwsys_stl::string* variable, const kwsys_stl::string& value) +{ + *variable = value; +} + +//---------------------------------------------------------------------------- +void CommandLineArguments::PopulateVariable( + kwsys_stl::vector* variable, const kwsys_stl::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( + kwsys_stl::vector* variable, const kwsys_stl::string& value) +{ + char* res = 0; + variable->push_back(static_cast(strtol(value.c_str(), &res, 10))); + //if ( res && *res ) + // { + // Can handle non-int + // } +} + +//---------------------------------------------------------------------------- +void CommandLineArguments::PopulateVariable( + kwsys_stl::vector* variable, const kwsys_stl::string& value) +{ + char* res = 0; + variable->push_back(strtod(value.c_str(), &res)); + //if ( res && *res ) + // { + // Can handle non-int + // } +} + +//---------------------------------------------------------------------------- +void CommandLineArguments::PopulateVariable( + kwsys_stl::vector* variable, const kwsys_stl::string& value) +{ + char* var = new char[ value.size() + 1 ]; + strcpy(var, value.c_str()); + variable->push_back(var); +} + +//---------------------------------------------------------------------------- +void CommandLineArguments::PopulateVariable( + kwsys_stl::vector* variable, + const kwsys_stl::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 ) + { + kwsys_stl::string var = "1"; + if ( value ) + { + var = value; + } + switch ( cs->VariableType ) + { + case CommandLineArguments::INT_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::DOUBLE_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::STRING_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::STL_STRING_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::BOOL_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::VECTOR_BOOL_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), var); + break; + case CommandLineArguments::VECTOR_INT_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), var); + break; + case CommandLineArguments::VECTOR_DOUBLE_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), var); + break; + case CommandLineArguments::VECTOR_STRING_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), var); + break; + case CommandLineArguments::VECTOR_STL_STRING_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), var); + break; + default: + kwsys_ios::cerr << "Got unknown variable type: \"" << cs->VariableType << "\"" << kwsys_ios::endl; + this->Internals->LastArgument --; + return 0; + } + } + return 1; +} + + +} // namespace KWSYS_NAMESPACE diff --git a/CommandLineArguments.hxx.in b/CommandLineArguments.hxx.in new file mode 100644 index 000000000..68e9600ef --- /dev/null +++ b/CommandLineArguments.hxx.in @@ -0,0 +1,286 @@ +/*============================================================================ + 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 <@KWSYS_NAMESPACE@/stl/string> +#include <@KWSYS_NAMESPACE@/stl/vector> + +/* Define this macro temporarily to keep the code readable. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsys_stl @KWSYS_NAMESPACE@_stl +#endif + +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 apropriate 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() ) + * { + * kwsys_ios::cerr << "Problem parsing arguments" << kwsys_ios::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 vairable 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 apropriate 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 + * apropriate 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, + kwsys_stl::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 + * apropriate type. This will handle the multi argument values. + */ + void AddArgument(const char* argument, ArgumentTypeEnum type, + kwsys_stl::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + kwsys_stl::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + kwsys_stl::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + kwsys_stl::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + kwsys_stl::vector* 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, + kwsys_stl::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(kwsys_stl::vector* matches, + const kwsys_stl::string& arg); + + //! Populate individual variables + bool PopulateVariable(CommandLineArgumentsCallbackStructure* cs, + const char* value); + + //! Populate individual variables of type ... + void PopulateVariable(bool* variable, const kwsys_stl::string& value); + void PopulateVariable(int* variable, const kwsys_stl::string& value); + void PopulateVariable(double* variable, const kwsys_stl::string& value); + void PopulateVariable(char** variable, const kwsys_stl::string& value); + void PopulateVariable(kwsys_stl::string* variable, const kwsys_stl::string& value); + void PopulateVariable(kwsys_stl::vector* variable, const kwsys_stl::string& value); + void PopulateVariable(kwsys_stl::vector* variable, const kwsys_stl::string& value); + void PopulateVariable(kwsys_stl::vector* variable, const kwsys_stl::string& value); + void PopulateVariable(kwsys_stl::vector* variable, const kwsys_stl::string& value); + void PopulateVariable(kwsys_stl::vector* variable, const kwsys_stl::string& value); + + typedef CommandLineArgumentsInternal Internal; + Internal* Internals; + kwsys_stl::string Help; + + unsigned int LineLength; + + bool StoreUnusedArgumentsFlag; +}; + +} // namespace @KWSYS_NAMESPACE@ + +/* Undefine temporary macro. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsys_stl +#endif + +#endif + + + + + diff --git a/Configure.h.in b/Configure.h.in new file mode 100644 index 000000000..15986cfea --- /dev/null +++ b/Configure.h.in @@ -0,0 +1,145 @@ +/*============================================================================ + 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@ + +/* If we are building a kwsys .c or .cxx file, suppress the Microsoft + deprecation warnings. */ +#if defined(KWSYS_NAMESPACE) +# ifndef _CRT_NONSTDC_NO_DEPRECATE +# define _CRT_NONSTDC_NO_DEPRECATE +# endif +# ifndef _CRT_SECURE_NO_DEPRECATE +# define _CRT_SECURE_NO_DEPRECATE +# endif +# ifndef _SCL_SECURE_NO_DEPRECATE +# define _SCL_SECURE_NO_DEPRECATE +# endif +#endif + +/* 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 +#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/Configure.hxx.in b/Configure.hxx.in new file mode 100644 index 000000000..716b84f09 --- /dev/null +++ b/Configure.hxx.in @@ -0,0 +1,175 @@ +/*============================================================================ + 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 ANSI C++ stream headers are to be used. */ +#define @KWSYS_NAMESPACE@_IOS_USE_ANSI @KWSYS_IOS_USE_ANSI@ + +/* Whether ANSI C++ streams are in std namespace. */ +#define @KWSYS_NAMESPACE@_IOS_HAVE_STD @KWSYS_IOS_HAVE_STD@ + +/* Whether ANSI C++ header is to be used. */ +#define @KWSYS_NAMESPACE@_IOS_USE_SSTREAM @KWSYS_IOS_USE_SSTREAM@ + +/* Whether old C++ header is to be used. */ +#define @KWSYS_NAMESPACE@_IOS_USE_STRSTREAM_H @KWSYS_IOS_USE_STRSTREAM_H@ + +/* Whether old C++ header is to be used. */ +#define @KWSYS_NAMESPACE@_IOS_USE_STRSTREA_H @KWSYS_IOS_USE_STRSTREA_H@ + +/* Whether C++ streams support the ios::binary openmode. */ +#define @KWSYS_NAMESPACE@_IOS_HAVE_BINARY @KWSYS_IOS_HAVE_BINARY@ + +/* Whether STL is in std namespace. */ +#define @KWSYS_NAMESPACE@_STL_HAVE_STD @KWSYS_STL_HAVE_STD@ + +/* Whether the STL string has operator<< for ostream. */ +#define @KWSYS_NAMESPACE@_STL_STRING_HAVE_OSTREAM @KWSYS_STL_STRING_HAVE_OSTREAM@ + +/* Whether the STL string has operator>> for istream. */ +#define @KWSYS_NAMESPACE@_STL_STRING_HAVE_ISTREAM @KWSYS_STL_STRING_HAVE_ISTREAM@ + +/* Whether the STL string has operator!= for char*. */ +#define @KWSYS_NAMESPACE@_STL_STRING_HAVE_NEQ_CHAR @KWSYS_STL_STRING_HAVE_NEQ_CHAR@ + +/* Define the stl namespace macro. */ +#if @KWSYS_NAMESPACE@_STL_HAVE_STD +# define @KWSYS_NAMESPACE@_stl std +#else +# define @KWSYS_NAMESPACE@_stl +#endif + +/* Define the ios namespace macro. */ +#if @KWSYS_NAMESPACE@_IOS_HAVE_STD +# define @KWSYS_NAMESPACE@_ios_namespace std +#else +# define @KWSYS_NAMESPACE@_ios_namespace +#endif +#if @KWSYS_NAMESPACE@_IOS_USE_SSTREAM +# define @KWSYS_NAMESPACE@_ios @KWSYS_NAMESPACE@_ios_namespace +#else +# define @KWSYS_NAMESPACE@_ios @KWSYS_NAMESPACE@_ios +#endif + +/* Define the ios::binary openmode macro. */ +#if @KWSYS_NAMESPACE@_IOS_HAVE_BINARY +# define @KWSYS_NAMESPACE@_ios_binary @KWSYS_NAMESPACE@_ios::ios::binary +#else +# define @KWSYS_NAMESPACE@_ios_binary 0 +#endif + +/* Whether the cstddef header is available. */ +#define @KWSYS_NAMESPACE@_CXX_HAS_CSTDDEF @KWSYS_CXX_HAS_CSTDDEF@ + +/* Whether the compiler supports null template arguments. */ +#define @KWSYS_NAMESPACE@_CXX_HAS_NULL_TEMPLATE_ARGS @KWSYS_CXX_HAS_NULL_TEMPLATE_ARGS@ + +/* Define the null template arguments macro. */ +#if @KWSYS_NAMESPACE@_CXX_HAS_NULL_TEMPLATE_ARGS +# define @KWSYS_NAMESPACE@_CXX_NULL_TEMPLATE_ARGS <> +#else +# define @KWSYS_NAMESPACE@_CXX_NULL_TEMPLATE_ARGS +#endif + +/* Whether the compiler supports member templates. */ +#define @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES @KWSYS_CXX_HAS_MEMBER_TEMPLATES@ + +/* Whether the compiler supports argument dependent lookup. */ +#define @KWSYS_NAMESPACE@_CXX_HAS_ARGUMENT_DEPENDENT_LOOKUP @KWSYS_CXX_HAS_ARGUMENT_DEPENDENT_LOOKUP@ + +/* Whether the compiler supports standard full specialization syntax. */ +#define @KWSYS_NAMESPACE@_CXX_HAS_FULL_SPECIALIZATION @KWSYS_CXX_HAS_FULL_SPECIALIZATION@ + +/* Define the specialization definition macro. */ +#if @KWSYS_NAMESPACE@_CXX_HAS_FULL_SPECIALIZATION +# define @KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION template <> +#else +# define @KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +#endif + +/* Define typename keyword macro for use in declarations. */ +#if defined(_MSC_VER) && _MSC_VER < 1300 +# define @KWSYS_NAMESPACE@_CXX_DECL_TYPENAME +#else +# define @KWSYS_NAMESPACE@_CXX_DECL_TYPENAME typename +#endif + +/* Whether the stl has iterator_traits. */ +#define @KWSYS_NAMESPACE@_STL_HAS_ITERATOR_TRAITS @KWSYS_STL_HAS_ITERATOR_TRAITS@ + +/* Whether the stl has iterator_category. */ +#define @KWSYS_NAMESPACE@_STL_HAS_ITERATOR_CATEGORY @KWSYS_STL_HAS_ITERATOR_CATEGORY@ + +/* Whether the stl has __iterator_category. */ +#define @KWSYS_NAMESPACE@_STL_HAS___ITERATOR_CATEGORY @KWSYS_STL_HAS___ITERATOR_CATEGORY@ + +/* Whether the stl allocator is the standard template. */ +#define @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_TEMPLATE @KWSYS_STL_HAS_ALLOCATOR_TEMPLATE@ + +/* Whether the stl allocator is not a template. */ +#define @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_NONTEMPLATE @KWSYS_STL_HAS_ALLOCATOR_NONTEMPLATE@ + +/* Whether the stl allocator has rebind. */ +#define @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_REBIND @KWSYS_STL_HAS_ALLOCATOR_REBIND@ + +/* Whether the stl allocator has a size argument for max_size. */ +#define @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_MAX_SIZE_ARGUMENT @KWSYS_STL_HAS_ALLOCATOR_MAX_SIZE_ARGUMENT@ + +/* Whether the stl containers support allocator objects. */ +#define @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_OBJECTS @KWSYS_STL_HAS_ALLOCATOR_OBJECTS@ + +/* Whether struct stat has the st_mtim member for high resolution times. */ +#define @KWSYS_NAMESPACE@_STAT_HAS_ST_MTIM @KWSYS_STAT_HAS_ST_MTIM@ + +/* 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_stl @KWSYS_NAMESPACE@_stl +# define kwsys_ios @KWSYS_NAMESPACE@_ios +# define kwsys @KWSYS_NAMESPACE@ +# define kwsys_ios_binary @KWSYS_NAMESPACE@_ios_binary +# endif +# define KWSYS_NAME_IS_KWSYS @KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define KWSYS_STL_HAVE_STD @KWSYS_NAMESPACE@_STL_HAVE_STD +# define KWSYS_IOS_HAVE_STD @KWSYS_NAMESPACE@_IOS_HAVE_STD +# define KWSYS_IOS_USE_ANSI @KWSYS_NAMESPACE@_IOS_USE_ANSI +# define KWSYS_IOS_USE_SSTREAM @KWSYS_NAMESPACE@_IOS_USE_SSTREAM +# define KWSYS_IOS_USE_STRSTREAM_H @KWSYS_NAMESPACE@_IOS_USE_STRSTREAM_H +# define KWSYS_IOS_USE_STRSTREA_H @KWSYS_NAMESPACE@_IOS_USE_STRSTREA_H +# define KWSYS_IOS_HAVE_BINARY @KWSYS_NAMESPACE@_IOS_HAVE_BINARY +# define KWSYS_STAT_HAS_ST_MTIM @KWSYS_NAMESPACE@_STAT_HAS_ST_MTIM +# define KWSYS_CXX_HAS_CSTDDEF @KWSYS_NAMESPACE@_CXX_HAS_CSTDDEF +# define KWSYS_STL_STRING_HAVE_OSTREAM @KWSYS_NAMESPACE@_STL_STRING_HAVE_OSTREAM +# define KWSYS_STL_STRING_HAVE_ISTREAM @KWSYS_NAMESPACE@_STL_STRING_HAVE_ISTREAM +# define KWSYS_STL_STRING_HAVE_NEQ_CHAR @KWSYS_NAMESPACE@_STL_STRING_HAVE_NEQ_CHAR +# define KWSYS_CXX_NULL_TEMPLATE_ARGS @KWSYS_NAMESPACE@_CXX_NULL_TEMPLATE_ARGS +# define KWSYS_CXX_HAS_MEMBER_TEMPLATES @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES +# define KWSYS_CXX_HAS_FULL_SPECIALIZATION @KWSYS_NAMESPACE@_CXX_HAS_FULL_SPECIALIZATION +# define KWSYS_CXX_DEFINE_SPECIALIZATION @KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +# define KWSYS_CXX_DECL_TYPENAME @KWSYS_NAMESPACE@_CXX_DECL_TYPENAME +# define KWSYS_STL_HAS_ALLOCATOR_REBIND @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_REBIND +# define KWSYS_STL_HAS_ALLOCATOR_MAX_SIZE_ARGUMENT @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_MAX_SIZE_ARGUMENT +# define KWSYS_CXX_HAS_ARGUMENT_DEPENDENT_LOOKUP @KWSYS_NAMESPACE@_CXX_HAS_ARGUMENT_DEPENDENT_LOOKUP +# define KWSYS_STL_HAS_ITERATOR_TRAITS @KWSYS_NAMESPACE@_STL_HAS_ITERATOR_TRAITS +# define KWSYS_STL_HAS_ITERATOR_CATEGORY @KWSYS_NAMESPACE@_STL_HAS_ITERATOR_CATEGORY +# define KWSYS_STL_HAS___ITERATOR_CATEGORY @KWSYS_NAMESPACE@_STL_HAS___ITERATOR_CATEGORY +# define KWSYS_STL_HAS_ALLOCATOR_TEMPLATE @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_TEMPLATE +# define KWSYS_STL_HAS_ALLOCATOR_NONTEMPLATE @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_NONTEMPLATE +# define KWSYS_STL_HAS_ALLOCATOR_OBJECTS @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_OBJECTS +#endif + +#endif diff --git a/Copyright.txt b/Copyright.txt new file mode 100644 index 000000000..1549a7d5f --- /dev/null +++ b/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/Directory.cxx b/Directory.cxx new file mode 100644 index 000000000..b88474781 --- /dev/null +++ b/Directory.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(Directory.hxx) + +#include KWSYS_HEADER(Configure.hxx) + +#include KWSYS_HEADER(stl/string) +#include KWSYS_HEADER(stl/vector) + +// 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 "kwsys_stl.hxx.in" +# include "kwsys_stl_string.hxx.in" +# include "kwsys_stl_vector.hxx.in" +#endif + +namespace KWSYS_NAMESPACE +{ + +//---------------------------------------------------------------------------- +class DirectoryInternals +{ +public: + // Array of Files + kwsys_stl::vector Files; + + // Path to Open'ed directory + kwsys_stl::string Path; +}; + +//---------------------------------------------------------------------------- +Directory::Directory() +{ + this->Internal = new DirectoryInternals; +} + +//---------------------------------------------------------------------------- +Directory::~Directory() +{ + delete this->Internal; +} + +//---------------------------------------------------------------------------- +unsigned long Directory::GetNumberOfFiles() const +{ + return static_cast(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 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace KWSYS_NAMESPACE +{ + +bool Directory::Load(const char* name) +{ + this->Clear(); +#if _MSC_VER < 1300 + long srchHandle; +#else + intptr_t srchHandle; +#endif + char* buf; + size_t n = strlen(name); + if ( name[n - 1] == '/' ) + { + buf = new char[n + 1 + 1]; + sprintf(buf, "%s*", name); + } + else + { + buf = new char[n + 2 + 1]; + sprintf(buf, "%s/*", name); + } + struct _finddata_t data; // data of current file + + // Now put them into the file array + srchHandle = _findfirst(buf, &data); + delete [] buf; + + if ( srchHandle == -1 ) + { + return 0; + } + + // Loop through names + do + { + this->Internal->Files.push_back(data.name); + } + while ( _findnext(srchHandle, &data) != -1 ); + this->Internal->Path = name; + return _findclose(srchHandle) != -1; +} + +unsigned long Directory::GetNumberOfFilesInDirectory(const char* name) +{ +#if _MSC_VER < 1300 + long srchHandle; +#else + intptr_t srchHandle; +#endif + char* buf; + size_t n = strlen(name); + if ( name[n - 1] == '/' ) + { + buf = new char[n + 1 + 1]; + sprintf(buf, "%s*", name); + } + else + { + buf = new char[n + 2 + 1]; + sprintf(buf, "%s/*", name); + } + struct _finddata_t data; // data of current file + + // Now put them into the file array + srchHandle = _findfirst(buf, &data); + delete [] buf; + + if ( srchHandle == -1 ) + { + return 0; + } + + // Loop through names + unsigned long count = 0; + do + { + count++; + } + while ( _findnext(srchHandle, &data) != -1 ); + _findclose(srchHandle); + return count; +} + +} // namespace KWSYS_NAMESPACE + +#else + +// Now the POSIX style directory access + +#include +#include + +/* There is a problem with the Portland compiler, large file +support and glibc/Linux system headers: +http://www.pgroup.com/userforum/viewtopic.php? +p=1992&sid=f16167f51964f1a68fe5041b8eb213b6 +*/ +#if defined(__PGI) && defined(__USE_FILE_OFFSET64) +# define dirent dirent64 +#endif + +namespace KWSYS_NAMESPACE +{ + +bool Directory::Load(const char* name) +{ + this->Clear(); + + if (!name) + { + return 0; + } + DIR* dir = opendir(name); + + if (!dir) + { + return 0; + } + + for (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 char* name) +{ + DIR* dir = opendir(name); + + if (!dir) + { + return 0; + } + + unsigned long count = 0; + for (dirent* d = readdir(dir); d; d = readdir(dir) ) + { + count++; + } + closedir(dir); + return count; +} + +} // namespace KWSYS_NAMESPACE + +#endif diff --git a/Directory.hxx.in b/Directory.hxx.in new file mode 100644 index 000000000..05217c46d --- /dev/null +++ b/Directory.hxx.in @@ -0,0 +1,80 @@ +/*============================================================================ + 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> + +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 char*); + + /** + * 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 char*); + + /** + * 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/DynamicLoader.cxx b/DynamicLoader.cxx new file mode 100644 index 000000000..c4ee09551 --- /dev/null +++ b/DynamicLoader.cxx @@ -0,0 +1,482 @@ +/*============================================================================ + 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 +#include +#define DYNAMICLOADER_DEFINED 1 + +namespace KWSYS_NAMESPACE +{ + +//---------------------------------------------------------------------------- +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const char* libname ) +{ + return shl_load(libname, BIND_DEFERRED | DYNAMIC_PATH, 0L); +} + +//---------------------------------------------------------------------------- +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + return !shl_unload(lib); +} + +//---------------------------------------------------------------------------- +DynamicLoader::SymbolPointer +DynamicLoader::GetSymbolAddress(DynamicLoader::LibraryHandle lib, const char* 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, TYPE_UNDEFINED, &addr); + void* result = (status < 0) ? (void*)0 : addr; + + // Hack to cast pointer-to-data to pointer-to-function. + return *reinterpret_cast(&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 ): + * 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 // for strlen +#include +#define DYNAMICLOADER_DEFINED 1 + +namespace KWSYS_NAMESPACE +{ + +//---------------------------------------------------------------------------- +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const char* libname ) +{ + NSObjectFileImageReturnCode rc; + NSObjectFileImage image = 0; + + rc = NSCreateObjectFileImageFromFile(libname, &image); + // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file + if( rc != NSObjectFileImageSuccess ) + { + return 0; + } + NSModule handle = NSLinkModule(image, libname, + 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 char* sym) +{ + void *result=0; + // Need to prepend symbols with '_' on Apple-gcc compilers + size_t len = strlen(sym); + char *rsym = new char[len + 1 + 1]; + strcpy(rsym, "_"); + strcat(rsym+1, sym); + + 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(&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 +#define DYNAMICLOADER_DEFINED 1 + +namespace KWSYS_NAMESPACE +{ + +//---------------------------------------------------------------------------- +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const char* libname) +{ + DynamicLoader::LibraryHandle lh; +#ifdef UNICODE + wchar_t libn[MB_CUR_MAX]; + mbstowcs(libn, libname, MB_CUR_MAX); + lh = LoadLibrary(libn); +#else + lh = LoadLibrary(libname); +#endif + return lh; +} + +//---------------------------------------------------------------------------- +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + return (int)FreeLibrary(lib); +} + +//---------------------------------------------------------------------------- +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const char* 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 = strlen(sym); + char *rsym = new char[len + 1 + 1]; + strcpy(rsym, "_"); + strcat(rsym, sym); +#else + const char *rsym = sym; +#endif +#ifdef UNICODE + wchar_t wsym[MB_CUR_MAX]; + mbstowcs(wsym, rsym, MB_CUR_MAX); + result = GetProcAddress(lib, wsym); +#else + result = (void*)GetProcAddress(lib, rsym); +#endif +#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(&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 // for strerror() + +#include +#include + +#define DYNAMICLOADER_DEFINED 1 + +namespace KWSYS_NAMESPACE +{ + +static image_id last_dynamic_err = B_OK; + +//---------------------------------------------------------------------------- +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const char* 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); + 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 char* 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,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 // for strerror() +#define DYNAMICLOADER_DEFINED 1 + +namespace KWSYS_NAMESPACE +{ + +//---------------------------------------------------------------------------- +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const char* libname ) +{ + return 0; +} + +//---------------------------------------------------------------------------- +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (!lib) + { + return 0; + } + + return 1; +} + +//---------------------------------------------------------------------------- +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const char* sym) +{ + return 0; +} + +//---------------------------------------------------------------------------- +const char* DynamicLoader::LastError() + { + return "General error"; + } + +} // 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 + +namespace KWSYS_NAMESPACE +{ + +//---------------------------------------------------------------------------- +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const char* libname ) +{ + return dlopen(libname, 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 char* sym) +{ + // Hack to cast pointer-to-data to pointer-to-function. + union + { + void* pvoid; + DynamicLoader::SymbolPointer psym; + } result; + result.pvoid = dlsym(lib, sym); + return result.psym; +} + +//---------------------------------------------------------------------------- +const char* DynamicLoader::LastError() +{ + return dlerror(); +} + +} // namespace KWSYS_NAMESPACE + +#endif diff --git a/DynamicLoader.hxx.in b/DynamicLoader.hxx.in new file mode 100644 index 000000000..64468ecd3 --- /dev/null +++ b/DynamicLoader.hxx.in @@ -0,0 +1,101 @@ +/*============================================================================ + 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.h> + +#if defined(__hpux) + #include +#elif defined(_WIN32) && !defined(__CYGWIN__) + #include +#elif defined(__APPLE__) + #include + #if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 + #include + #endif +#elif defined(__BEOS__) + #include +#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 char*); + + /** 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 char*); + + /** 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/EncodeExecutable.c b/EncodeExecutable.c new file mode 100644 index 000000000..bc30568ff --- /dev/null +++ b/EncodeExecutable.c @@ -0,0 +1,114 @@ +/*============================================================================ + 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 +#ifdef __WATCOMC__ +#define _unlink unlink +#endif +int main(int argc, char* argv[]) +{ + FILE* ifp; + FILE* ofp; + int i; + int n; + int count = 0; + unsigned char buffer[1024]; + + /* Check arguments. */ + if(argc != 5) + { + fprintf(stderr, "Usage: %s \n", + argv[0]); + return 1; + } + + /* Open the input file. */ + ifp = fopen(argv[1], "rb"); + if(!ifp) + { + fprintf(stderr, "Cannot open input file: \"%s\"\n", argv[1]); + return 2; + } + ofp = fopen(argv[2], "w"); + if(!ofp) + { + fprintf(stderr, "Cannot open output file: \"%s\"\n", argv[2]); + fclose(ifp); + return 2; + } + + /* Prepend header comment. */ + fprintf(ofp, "/*\n * DO NOT EDIT\n * This file is generated by:\n"); + fprintf(ofp, " * %s\n */\n\n", argv[0]); + fprintf(ofp, "#include \"kwsysPrivate.h\"\n"); + fprintf(ofp, "#include KWSYS_HEADER(Configure.h)\n\n"); + fprintf(ofp, "#include \n\n"); + fprintf(ofp, "#if defined(_WIN32)\n"); + fprintf(ofp, "# include \n"); + fprintf(ofp, "#else\n"); + fprintf(ofp, "# include \n"); + fprintf(ofp, "#endif\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "static void kwsys_unlink(const char* fname)\n"); + fprintf(ofp, "{\n"); + fprintf(ofp, "#if defined(__WATCOMC__)\n"); + fprintf(ofp, " unlink(fname);\n"); + fprintf(ofp, "#else\n"); + fprintf(ofp, " _unlink(fname);\n"); + fprintf(ofp, "#endif\n"); + fprintf(ofp, "}\n"); + fprintf(ofp, "\n"); + + /* Split file up in 1024-byte chunks. */ + while((n = (int)fread(buffer, 1, 1024, ifp)) > 0) + { + fprintf(ofp, "static unsigned char kwsysEncodedArray%s_%d[%d] = {\n", + argv[4], count++, n); + for(i=0; i < n-1; ++i) + { + fprintf(ofp, "0x%02X", buffer[i]); + if(i%10 == 9) + { + fprintf(ofp, ",\n"); + } + else + { + fprintf(ofp, ", "); + } + } + fprintf(ofp, "0x%02X};\n\n", buffer[n-1]); + } + fclose(ifp); + + /* Provide a function to write the data to a file. */ + fprintf(ofp, "extern %s_EXPORT int %sEncodedWriteArray%s(const char* fname)\n", + argv[3], argv[3], argv[4]); + fprintf(ofp, "{\n"); + fprintf(ofp, " FILE* ofp = fopen(fname, \"wb\");\n"); + fprintf(ofp, " if(!ofp) { return 0; }\n"); + for(i=0; i < count; ++i) + { + fprintf(ofp, " if(fwrite(kwsysEncodedArray%s_%d, 1,\n" + " sizeof(kwsysEncodedArray%s_%d), ofp) !=\n" + " sizeof(kwsysEncodedArray%s_%d))\n", + argv[4], i, argv[4], i, argv[4], i); + fprintf(ofp, " {\n"); + fprintf(ofp, " fclose(ofp);\n"); + fprintf(ofp, " kwsys_unlink(fname);\n"); + fprintf(ofp, " return 0;\n"); + fprintf(ofp, " }\n"); + } + fprintf(ofp, " fclose(ofp);\n"); + fprintf(ofp, " return 1;\n"); + fprintf(ofp, "}\n"); + fclose(ofp); + return 0; +} diff --git a/ExtraTest.cmake.in b/ExtraTest.cmake.in new file mode 100644 index 000000000..e8c0a1cdb --- /dev/null +++ b/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/FundamentalType.h.in b/FundamentalType.h.in new file mode 100644 index 000000000..ff200633a --- /dev/null +++ b/FundamentalType.h.in @@ -0,0 +1,146 @@ +/*============================================================================ + 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@_FundamentalType_h +#define @KWSYS_NAMESPACE@_FundamentalType_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 kwsysFundamentalType kwsys_ns(FundamentalType) +# define kwsysFundamentalType_Int8 kwsys_ns(FundamentalType_Int8) +# define kwsysFundamentalType_UInt8 kwsys_ns(FundamentalType_UInt8) +# define kwsysFundamentalType_Int16 kwsys_ns(FundamentalType_Int16) +# define kwsysFundamentalType_UInt16 kwsys_ns(FundamentalType_UInt16) +# define kwsysFundamentalType_Int32 kwsys_ns(FundamentalType_Int32) +# define kwsysFundamentalType_UInt32 kwsys_ns(FundamentalType_UInt32) +# define kwsysFundamentalType_Int64 kwsys_ns(FundamentalType_Int64) +# define kwsysFundamentalType_UInt64 kwsys_ns(FundamentalType_UInt64) +#endif + +/* The size of fundamental types. Types that do not exist have size 0. */ +@KWSYS_C_CODE_SIZEOF_CHAR@ +@KWSYS_C_CODE_SIZEOF_SHORT@ +@KWSYS_C_CODE_SIZEOF_INT@ +@KWSYS_C_CODE_SIZEOF_LONG@ +@KWSYS_C_CODE_SIZEOF_LONG_LONG@ +@KWSYS_C_CODE_SIZEOF___INT64@ + +/* Whether types "long long" and "__int64" are enabled. If a type is + enabled then it is a unique fundamental type. */ +#define @KWSYS_NAMESPACE@_USE_LONG_LONG @KWSYS_USE_LONG_LONG@ +#define @KWSYS_NAMESPACE@_USE___INT64 @KWSYS_USE___INT64@ + +/* Whether type "char" is signed (it may be signed or unsigned). */ +#define @KWSYS_NAMESPACE@_CHAR_IS_SIGNED @KWSYS_CHAR_IS_SIGNED@ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Select an 8-bit integer type. */ +#if @KWSYS_NAMESPACE@_SIZEOF_CHAR == 1 +typedef signed char kwsysFundamentalType_Int8; +typedef unsigned char kwsysFundamentalType_UInt8; +#else +# error "No native data type can represent an 8-bit integer." +#endif + +/* Select a 16-bit integer type. */ +#if @KWSYS_NAMESPACE@_SIZEOF_SHORT == 2 +typedef short kwsysFundamentalType_Int16; +typedef unsigned short kwsysFundamentalType_UInt16; +#elif @KWSYS_NAMESPACE@_SIZEOF_INT == 2 +typedef int kwsysFundamentalType_Int16; +typedef unsigned int kwsysFundamentalType_UInt16; +#else +# error "No native data type can represent a 16-bit integer." +#endif + +/* Select a 32-bit integer type. */ +#if @KWSYS_NAMESPACE@_SIZEOF_INT == 4 +typedef int kwsysFundamentalType_Int32; +typedef unsigned int kwsysFundamentalType_UInt32; +#elif @KWSYS_NAMESPACE@_SIZEOF_LONG == 4 +typedef long kwsysFundamentalType_Int32; +typedef unsigned long kwsysFundamentalType_UInt32; +#else +# error "No native data type can represent a 32-bit integer." +#endif + +/* Select a 64-bit integer type. */ +#if @KWSYS_NAMESPACE@_SIZEOF_LONG == 8 +typedef signed long kwsysFundamentalType_Int64; +typedef unsigned long kwsysFundamentalType_UInt64; +/* Whether UInt64 can be converted to double. */ +# define @KWSYS_NAMESPACE@_CAN_CONVERT_UI64_TO_DOUBLE 1 +#elif @KWSYS_NAMESPACE@_USE_LONG_LONG && @KWSYS_NAMESPACE@_SIZEOF_LONG_LONG == 8 +typedef signed long long kwsysFundamentalType_Int64; +typedef unsigned long long kwsysFundamentalType_UInt64; +/* Whether UInt64 can be converted to double. */ +# define @KWSYS_NAMESPACE@_CAN_CONVERT_UI64_TO_DOUBLE 1 +#elif @KWSYS_NAMESPACE@_USE___INT64 && @KWSYS_NAMESPACE@_SIZEOF___INT64 == 8 +typedef signed __int64 kwsysFundamentalType_Int64; +typedef unsigned __int64 kwsysFundamentalType_UInt64; +/* Whether UInt64 can be converted to double. */ +# define @KWSYS_NAMESPACE@_CAN_CONVERT_UI64_TO_DOUBLE @KWSYS_CAN_CONVERT_UI64_TO_DOUBLE@ +#else +# error "No native data type can represent a 64-bit integer." +#endif + +#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 kwsysFundamentalType +# undef kwsysFundamentalType_Int8 +# undef kwsysFundamentalType_UInt8 +# undef kwsysFundamentalType_Int16 +# undef kwsysFundamentalType_UInt16 +# undef kwsysFundamentalType_Int32 +# undef kwsysFundamentalType_UInt32 +# undef kwsysFundamentalType_Int64 +# undef kwsysFundamentalType_UInt64 +# endif +#endif + +/* If building a C or C++ file in kwsys itself, give the source file + access to the configured macros without a configured namespace. */ +#if defined(KWSYS_NAMESPACE) +# define KWSYS_SIZEOF_CHAR @KWSYS_NAMESPACE@_SIZEOF_CHAR +# define KWSYS_SIZEOF_SHORT @KWSYS_NAMESPACE@_SIZEOF_SHORT +# define KWSYS_SIZEOF_INT @KWSYS_NAMESPACE@_SIZEOF_INT +# define KWSYS_SIZEOF_LONG @KWSYS_NAMESPACE@_SIZEOF_LONG +# define KWSYS_SIZEOF_LONG_LONG @KWSYS_NAMESPACE@_SIZEOF_LONG_LONG +# define KWSYS_SIZEOF___INT64 @KWSYS_NAMESPACE@_SIZEOF___INT64 +# define KWSYS_USE_LONG_LONG @KWSYS_NAMESPACE@_USE_LONG_LONG +# define KWSYS_USE___INT64 @KWSYS_NAMESPACE@_USE___INT64 +# define KWSYS_CHAR_IS_SIGNED @KWSYS_NAMESPACE@_CHAR_IS_SIGNED +# define KWSYS_CAN_CONVERT_UI64_TO_DOUBLE @KWSYS_NAMESPACE@_CAN_CONVERT_UI64_TO_DOUBLE +#endif + +#endif diff --git a/Glob.cxx b/Glob.cxx new file mode 100644 index 000000000..513eb6408 --- /dev/null +++ b/Glob.cxx @@ -0,0 +1,516 @@ +/*============================================================================ + 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) +#include KWSYS_HEADER(stl/string) +#include KWSYS_HEADER(stl/vector) + +// 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" +# include "kwsys_stl.hxx.in" +# include "kwsys_stl_string.hxx.in" +#endif + +#include +#include +#include +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: + kwsys_stl::vector Files; + kwsys_stl::vector 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; +} + +//---------------------------------------------------------------------------- +Glob::~Glob() +{ + delete this->Internals; +} + +//---------------------------------------------------------------------------- +kwsys_stl::vector& Glob::GetFiles() +{ + return this->Internals->Files; +} + +//---------------------------------------------------------------------------- +kwsys_stl::string Glob::PatternToRegex(const kwsys_stl::string& pattern, + bool require_whole_string, + bool preserve_case) +{ + // Incrementally build the regular expression from the pattern. + kwsys_stl::string regex = require_whole_string? "^" : ""; + kwsys_stl::string::const_iterator pattern_first = pattern.begin(); + kwsys_stl::string::const_iterator pattern_last = pattern.end(); + for(kwsys_stl::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. + kwsys_stl::string::const_iterator bracket_first = i+1; + kwsys_stl::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. + kwsys_stl::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(ch)); + } + } + + if(require_whole_string) + { + regex += "$"; + } + return regex; +} + +//---------------------------------------------------------------------------- +void Glob::RecurseDirectory(kwsys_stl::string::size_type start, + const kwsys_stl::string& dir) +{ + kwsys::Directory d; + if ( !d.Load(dir.c_str()) ) + { + return; + } + unsigned long cc; + kwsys_stl::string fullname; + kwsys_stl::string realname; + kwsys_stl::string fname; + for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ ) + { + fname = d.GetFile(cc); + if ( strcmp(fname.c_str(), ".") == 0 || + strcmp(fname.c_str(), "..") == 0 ) + { + 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 + + if ( start == 0 ) + { + fullname = dir + fname; + } + else + { + fullname = dir + "/" + fname; + } + + bool isDir = kwsys::SystemTools::FileIsDirectory(realname.c_str()); + bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname.c_str()); + + if ( isDir && (!isSymLink || this->RecurseThroughSymlinks) ) + { + if (isSymLink) + { + ++this->FollowedSymlinkCount; + } + this->RecurseDirectory(start+1, realname); + } + else + { + if ( (this->Internals->Expressions.size() > 0) && + this->Internals->Expressions[ + this->Internals->Expressions.size()-1].find(fname.c_str()) ) + { + this->AddFile(this->Internals->Files, realname.c_str()); + } + } + } +} + +//---------------------------------------------------------------------------- +void Glob::ProcessDirectory(kwsys_stl::string::size_type start, + const kwsys_stl::string& dir) +{ + //kwsys_ios::cout << "ProcessDirectory: " << dir << kwsys_ios::endl; + bool last = ( start == this->Internals->Expressions.size()-1 ); + if ( last && this->Recurse ) + { + this->RecurseDirectory(start, dir); + return; + } + + if ( start >= this->Internals->Expressions.size() ) + { + return; + } + + kwsys::Directory d; + if ( !d.Load(dir.c_str()) ) + { + return; + } + unsigned long cc; + kwsys_stl::string fullname; + kwsys_stl::string realname; + kwsys_stl::string fname; + for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ ) + { + fname = d.GetFile(cc); + if ( strcmp(fname.c_str(), ".") == 0 || + strcmp(fname.c_str(), "..") == 0 ) + { + 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 + + if ( start == 0 ) + { + fullname = dir + fname; + } + else + { + fullname = dir + "/" + fname; + } + + //kwsys_ios::cout << "Look at file: " << fname << kwsys_ios::endl; + //kwsys_ios::cout << "Match: " + // << this->Internals->TextExpressions[start].c_str() << kwsys_ios::endl; + //kwsys_ios::cout << "Full name: " << fullname << kwsys_ios::endl; + + if ( !last && + !kwsys::SystemTools::FileIsDirectory(realname.c_str()) ) + { + continue; + } + + if ( this->Internals->Expressions[start].find(fname.c_str()) ) + { + if ( last ) + { + this->AddFile(this->Internals->Files, realname.c_str()); + } + else + { + this->ProcessDirectory(start+1, realname + "/"); + } + } + } +} + +//---------------------------------------------------------------------------- +bool Glob::FindFiles(const kwsys_stl::string& inexpr) +{ + kwsys_stl::string cexpr; + kwsys_stl::string::size_type cc; + kwsys_stl::string expr = inexpr; + + this->Internals->Expressions.clear(); + this->Internals->Files.clear(); + + if ( !kwsys::SystemTools::FileIsFullPath(expr.c_str()) ) + { + expr = kwsys::SystemTools::GetCurrentWorkingDirectory(); + expr += "/" + inexpr; + } + kwsys_stl::string fexpr = expr; + + kwsys_stl::string::size_type skip = 0; + kwsys_stl::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 ) + { + //kwsys_ios::cout << "I can skip: " << fexpr.substr(0, last_slash) + //<< kwsys_ios::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.size() > 0 ) + { + this->AddExpression(cexpr.c_str()); + } + cexpr = ""; + } + else + { + cexpr.append(1, static_cast(ch)); + } + } + if ( cexpr.size() > 0 ) + { + this->AddExpression(cexpr.c_str()); + } + + // Handle network paths + if ( skip > 0 ) + { + this->ProcessDirectory(0, fexpr.substr(0, skip) + "/"); + } + else + { + this->ProcessDirectory(0, "/"); + } + return true; +} + +//---------------------------------------------------------------------------- +void Glob::AddExpression(const char* expr) +{ + this->Internals->Expressions.push_back( + kwsys::RegularExpression( + this->PatternToRegex(expr).c_str())); +} + +//---------------------------------------------------------------------------- +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(kwsys_stl::vector& files, const char* file) +{ + if ( !this->Relative.empty() ) + { + files.push_back(kwsys::SystemTools::RelativePath(this->Relative.c_str(), file)); + } + else + { + files.push_back(file); + } +} + +} // namespace KWSYS_NAMESPACE + diff --git a/Glob.hxx.in b/Glob.hxx.in new file mode 100644 index 000000000..88c343ce0 --- /dev/null +++ b/Glob.hxx.in @@ -0,0 +1,117 @@ +/*============================================================================ + 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 <@KWSYS_NAMESPACE@/stl/string> +#include <@KWSYS_NAMESPACE@/stl/vector> + +/* Define this macro temporarily to keep the code readable. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsys_stl @KWSYS_NAMESPACE@_stl +#endif + +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: + Glob(); + ~Glob(); + + //! Find all files that match the pattern. + bool FindFiles(const kwsys_stl::string& inexpr); + + //! Return the list of files that matched. + kwsys_stl::vector& 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 kwsys_stl::string PatternToRegex(const kwsys_stl::string& pattern, + bool require_whole_string = true, + bool preserve_case = false); + +protected: + //! Process directory + void ProcessDirectory(kwsys_stl::string::size_type start, + const kwsys_stl::string& dir); + + //! Process last directory, but only when recurse flags is on. That is + // effectively like saying: /path/to/file/**/file + void RecurseDirectory(kwsys_stl::string::size_type start, + const kwsys_stl::string& dir); + + //! Add regular expression + void AddExpression(const char* expr); + + //! Add a file to the list + void AddFile(kwsys_stl::vector& files, const char* file); + + GlobInternals* Internals; + bool Recurse; + kwsys_stl::string Relative; + bool RecurseThroughSymlinks; + unsigned int FollowedSymlinkCount; + +private: + Glob(const Glob&); // Not implemented. + void operator=(const Glob&); // Not implemented. +}; + +} // namespace @KWSYS_NAMESPACE@ + +/* Undefine temporary macro. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsys_stl +#endif + +#endif diff --git a/IOStream.cxx b/IOStream.cxx new file mode 100644 index 000000000..57b696eb3 --- /dev/null +++ b/IOStream.cxx @@ -0,0 +1,281 @@ +/*============================================================================ + 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) + +// Configure the implementation for the current streams library. +#if !KWSYS_IOS_USE_ANSI +# define ios_base ios +# if defined(__HP_aCC) +# define protected public +# include // Hack access to some private stream methods. +# undef protected +# endif +#endif + +// Include the streams library. +#include KWSYS_HEADER(ios/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 "kwsys_ios_iostream.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 // sscanf, sprintf +# include // 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(kwsys_ios::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() & kwsys_ios::ios_base::basefield; + if(flags == kwsys_ios::ios_base::oct) { base = 8; } + else if(flags == kwsys_ios::ios_base::dec) { base = 10; } + else if(flags == kwsys_ios::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 +kwsys_ios::istream& +IOStreamScanTemplate(kwsys_ios::istream& is, T& value, char type) +{ + int state = kwsys_ios::ios_base::goodbit; + + // Skip leading whitespace. +# if KWSYS_IOS_USE_ANSI + kwsys_ios::istream::sentry okay(is); +# else + is.eatwhite(); + kwsys_ios::istream& okay = is; +# endif + + if(okay) + { +# if KWSYS_IOS_USE_ANSI + try { +# endif + // 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 |= kwsys_ios::ios_base::eofbit; } + if(!success) { state |= kwsys_ios::ios_base::failbit; } + else { value = result; } +# if KWSYS_IOS_USE_ANSI + } catch(...) { state |= kwsys_ios::ios_base::badbit; } +# endif + } + +# if KWSYS_IOS_USE_ANSI + is.setstate(kwsys_ios::ios_base::iostate(state)); +# else + is.clear(state); +# endif + return is; +} + +// Print an integer value to an output stream. +template +kwsys_ios::ostream& +IOStreamPrintTemplate(kwsys_ios::ostream& os, T value, char type) +{ +# if KWSYS_IOS_USE_ANSI + kwsys_ios::ostream::sentry okay(os); +# else + kwsys_ios::ostream& okay = os; +# endif + if(okay) + { +# if KWSYS_IOS_USE_ANSI + try { +# endif + // Construct the format string. + char format[8]; + char* f = format; + *f++ = '%'; + if(os.flags() & kwsys_ios::ios_base::showpos) { *f++ = '+'; } + if(os.flags() & kwsys_ios::ios_base::showbase) { *f++ = '#'; } +# if defined(_MSC_VER) + *f++ = 'I'; *f++ = '6'; *f++ = '4'; +# else + *f++ = 'l'; *f++ = 'l'; +# endif + long bflags = os.flags() & kwsys_ios::ios_base::basefield; + if(bflags == kwsys_ios::ios_base::oct) { *f++ = 'o'; } + else if(bflags != kwsys_ios::ios_base::hex) { *f++ = type; } + else if(os.flags() & kwsys_ios::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; +# if KWSYS_IOS_USE_ANSI + } catch(...) { os.clear(os.rdstate() | kwsys_ios::ios_base::badbit); } +# endif + } + return os; +} + +# if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG +// Implement input stream operator for IOStreamSLL. +kwsys_ios::istream& IOStreamScan(kwsys_ios::istream& is, IOStreamSLL& value) +{ + return IOStreamScanTemplate(is, value, 'd'); +} + +// Implement input stream operator for IOStreamULL. +kwsys_ios::istream& IOStreamScan(kwsys_ios::istream& is, IOStreamULL& value) +{ + return IOStreamScanTemplate(is, value, 'u'); +} +# endif + +# if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG +// Implement output stream operator for IOStreamSLL. +kwsys_ios::ostream& IOStreamPrint(kwsys_ios::ostream& os, IOStreamSLL value) +{ + return IOStreamPrintTemplate(os, value, 'd'); +} + +// Implement output stream operator for IOStreamULL. +kwsys_ios::ostream& IOStreamPrint(kwsys_ios::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() +{ +} + +} // namespace KWSYS_NAMESPACE + +#endif // KWSYS_IOS_NEED_OPERATORS_LL diff --git a/IOStream.hxx.in b/IOStream.hxx.in new file mode 100644 index 000000000..9eb99e058 --- /dev/null +++ b/IOStream.hxx.in @@ -0,0 +1,146 @@ +/*============================================================================ + 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 <@KWSYS_NAMESPACE@/ios/iosfwd> + +/* Define these macros temporarily to keep the code readable. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +# define kwsys_ios @KWSYS_NAMESPACE@_ios +#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@ + +/* Size of type long long and 0 if not available. */ +#define @KWSYS_NAMESPACE@_IOS_SIZEOF_LONG_LONG @KWSYS_SIZEOF_LONG_LONG@ + +/* Determine whether we need to define the streaming operators for + long long or __int64. */ +#if @KWSYS_NAMESPACE@_IOS_SIZEOF_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 kwsys_ios::istream& IOStreamScan(kwsys_ios::istream&, + IOStreamSLL&); +kwsysEXPORT kwsys_ios::istream& IOStreamScan(kwsys_ios::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 kwsys_ios::istream& +operator>>(kwsys_ios::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 kwsys_ios::istream& +operator>>(kwsys_ios::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 kwsys_ios::ostream& IOStreamPrint(kwsys_ios::ostream&, + IOStreamSLL); +kwsysEXPORT kwsys_ios::ostream& IOStreamPrint(kwsys_ios::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 kwsys_ios::ostream& +operator<<(kwsys_ios::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 kwsys_ios::ostream& +operator<<(kwsys_ios::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 +# undef kwsys_ios +#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_SIZEOF_LONG_LONG @KWSYS_NAMESPACE@_IOS_SIZEOF_LONG_LONG +# 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/MD5.c b/MD5.c new file mode 100644 index 000000000..56776a324 --- /dev/null +++ b/MD5.c @@ -0,0 +1,518 @@ +/*============================================================================ + 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 /* size_t */ +#include /* malloc, free */ +#include /* 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__) +# 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 + . 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 + 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 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__) +# 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) +{ + if(length < 0) + { + length = (int)strlen((char const*)data); + } + md5_append(&md5->md5_state, (md5_byte_t const*)data, (size_t)length); +} + +/*--------------------------------------------------------------------------*/ +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/MD5.h.in b/MD5.h.in new file mode 100644 index 000000000..33344317d --- /dev/null +++ b/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/Process.h.in b/Process.h.in new file mode 100644 index 000000000..c5995eac1 --- /dev/null +++ b/Process.h.in @@ -0,0 +1,428 @@ +/*============================================================================ + 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_Verbatim kwsys_ns(Process_Option_Verbatim) +# 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_Kill kwsys_ns(Process_Kill) +#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_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 + */ +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_Verbatim +}; + +/** + * 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); + +/** + * 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); + +#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_Verbatim +# 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_Kill +# endif +#endif + +#endif diff --git a/ProcessFwd9x.c b/ProcessFwd9x.c new file mode 100644 index 000000000..536c54b67 --- /dev/null +++ b/ProcessFwd9x.c @@ -0,0 +1,211 @@ +/*============================================================================ + 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. +============================================================================*/ + +/* + On Windows9x platforms, this executable is spawned between a parent + process and the child it is invoking to work around a bug. See the + Win32 implementation file for details. + + Future Work: This executable must be linked statically against the C + runtime library before being encoded into the library. Building it + in this way may be hard because CMake has limited abilities to build + different targets with different configurations in the same + directory. We may just have to create and encode the executable + once instead of generating it during the build. This would be an + acceptable solution because the forwarding executable should not + change very often and is pretty simple. +*/ + +#ifdef _MSC_VER +#pragma warning (push, 1) +#endif +#include +#include + +void ReportLastError(HANDLE errorPipe); + +int main() +{ + /* Process startup information for the real child. */ + STARTUPINFO si; + PROCESS_INFORMATION pi; + + /* The result of waiting for the child to exit. */ + DWORD waitResult; + + /* The child's process return code. */ + DWORD retVal; + + /* The command line used to invoke this process. */ + LPSTR commandLine = GetCommandLine(); + + /* Pointer that will be advanced to the beginning of the command + line of the real child process. */ + LPSTR cmdLine = commandLine; + + /* Handle to the error reporting pipe provided by the parent. This + is parsed off the command line. */ + HANDLE errorPipe = 0; + HANDLE errorPipeOrig = 0; + + /* Handle to the event the parent uses to tell us to resume the child. + This is parsed off the command line. */ + HANDLE resumeEvent = 0; + + /* Handle to the event the parent uses to tell us to kill the child. + This is parsed off the command line. */ + HANDLE killEvent = 0; + + /* Flag for whether to hide window of child process. */ + int hideWindow = 0; + + /* An array of the handles on which we wait when the child is + running. */ + HANDLE waitHandles[2] = {0, 0}; + + /* Move the pointer past the name of this executable. */ + if(*cmdLine == '"') + { + ++cmdLine; + while(*cmdLine && *cmdLine != '"') { ++cmdLine; } + if(*cmdLine) { ++cmdLine; } + } + else + { + while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } + } + + /* Parse the error pipe handle. */ + while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } + sscanf(cmdLine, "%p", &errorPipeOrig); + + /* Parse the resume event handle. */ + while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } + while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } + sscanf(cmdLine, "%p", &resumeEvent); + + /* Parse the kill event handle. */ + while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } + while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } + sscanf(cmdLine, "%p", &killEvent); + + /* Parse the hide window flag. */ + while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } + while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } + sscanf(cmdLine, "%d", &hideWindow); + + /* Skip to the beginning of the command line of the real child. */ + while(*cmdLine && *cmdLine != ' ') { ++cmdLine; } + while(*cmdLine && *cmdLine == ' ') { ++cmdLine; } + + /* Create a non-inherited copy of the error pipe. We do not want + the child to get it. */ + if(DuplicateHandle(GetCurrentProcess(), errorPipeOrig, + GetCurrentProcess(), &errorPipe, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + /* Have a non-inherited duplicate. Close the inherited one. */ + CloseHandle(errorPipeOrig); + } + else + { + /* Could not duplicate handle. Report the error. */ + ReportLastError(errorPipeOrig); + return 1; + } + + /* Create the subprocess. */ + ZeroMemory(&si, sizeof(si)); + ZeroMemory(&pi, sizeof(pi)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + si.wShowWindow = hideWindow?SW_HIDE:SW_SHOWDEFAULT; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if(CreateProcess(0, cmdLine, 0, 0, TRUE, CREATE_SUSPENDED, 0, 0, &si, &pi)) + { + /* Process created successfully. Close the error reporting pipe + to notify the parent of success. */ + CloseHandle(errorPipe); + } + else + { + /* Error creating the process. Report the error to the parent + process through the special error reporting pipe. */ + ReportLastError(errorPipe); + return 1; + } + + /* Wait for resume or kill event from parent. */ + waitHandles[0] = killEvent; + waitHandles[1] = resumeEvent; + waitResult = WaitForMultipleObjects(2, waitHandles, 0, INFINITE); + + /* Check what happened. */ + if(waitResult == WAIT_OBJECT_0) + { + /* We were asked to kill the child. */ + TerminateProcess(pi.hProcess, 255); + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return 1; + } + else + { + /* We were asked to resume the child. */ + ResumeThread(pi.hThread); + CloseHandle(pi.hThread); + } + + /* Wait for subprocess to exit or for kill event from parent. */ + waitHandles[0] = killEvent; + waitHandles[1] = pi.hProcess; + waitResult = WaitForMultipleObjects(2, waitHandles, 0, INFINITE); + + /* Check what happened. */ + if(waitResult == WAIT_OBJECT_0) + { + /* We were asked to kill the child. */ + TerminateProcess(pi.hProcess, 255); + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + return 1; + } + else + { + /* The child exited. Get the return code. */ + GetExitCodeProcess(pi.hProcess, &retVal); + CloseHandle(pi.hProcess); + return retVal; + } +} + +void ReportLastError(HANDLE errorPipe) +{ + LPVOID lpMsgBuf; + DWORD n; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + WriteFile(errorPipe, lpMsgBuf, strlen(lpMsgBuf)+1, &n, 0); + LocalFree( lpMsgBuf ); +} diff --git a/ProcessUNIX.c b/ProcessUNIX.c new file mode 100644 index 000000000..9c66a4486 --- /dev/null +++ b/ProcessUNIX.c @@ -0,0 +1,2753 @@ +/*============================================================================ + 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. + +*/ + +#include /* ptrdiff_t */ +#include /* snprintf */ +#include /* malloc, free */ +#include /* strdup, strerror, memset */ +#include /* struct timeval */ +#include /* pid_t, fd_set */ +#include /* waitpid */ +#include /* open mode */ +#include /* pipe, close, fork, execvp, select, _exit */ +#include /* fcntl */ +#include /* errno */ +#include /* gettimeofday */ +#include /* sigaction */ +#include /* DIR, dirent */ +#include /* isspace */ + +#ifdef __HAIKU__ +#undef __BEOS__ +#endif + +#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 +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) +# 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 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, int* readEnd); +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; + int NumberOfCommands; + + /* Descriptors for the read ends of the child's output pipes and + the signal pipe. */ + int PipeReadEnds[KWSYSPE_PIPE_COUNT]; + + /* 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. */ + pid_t* 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; + + /* 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. */ + int 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. */ + int 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]) + { + /* Out of memory. */ + 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) + { + 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; + } +} + +/*--------------------------------------------------------------------------*/ +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 = 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_Verbatim: return cp->Verbatim; + 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_Verbatim: cp->Verbatim = 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; + kwsysProcessCreateInformation si = {-1, -1, -1, {-1, -1}}; + + /* 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 stderr pipe to be shared by all processes. */ + { + /* 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]; + si.StdErr = 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); + kwsysProcessCleanupDescriptor(&si.StdErr); + return; + } + + /* Set to non-blocking in case select lies, or for the polling + implementation. */ + if(!kwsysProcessSetNonBlocking(p[0])) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupDescriptor(&si.StdErr); + return; + } + } + + /* Replace the stderr pipe with a file if requested. In this case + the select call will report that stderr is closed immediately. */ + if(cp->PipeFileSTDERR) + { + if(!kwsysProcessSetupOutputPipeFile(&si.StdErr, cp->PipeFileSTDERR)) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupDescriptor(&si.StdErr); + return; + } + } + + /* Replace the stderr pipe with the parent's if requested. In this + case the select call will report that stderr is closed + immediately. */ + if(cp->PipeSharedSTDERR) + { + kwsysProcessCleanupDescriptor(&si.StdErr); + si.StdErr = 2; + } + + /* Replace the stderr pipe with the native pipe provided if any. In + this case the select call will report that stderr is closed + immediately. */ + if(cp->PipeNativeSTDERR[1] >= 0) + { + if(!kwsysProcessSetupOutputPipeNative(&si.StdErr, cp->PipeNativeSTDERR)) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupDescriptor(&si.StdErr); + return; + } + } + + /* The timeout period starts now. */ + cp->StartTime = kwsysProcessTimeGetCurrent(); + cp->TimeoutTime.tv_sec = -1; + cp->TimeoutTime.tv_usec = -1; + + /* Create the pipeline of processes. */ + { + int readEnd = -1; + int failed = 0; + for(i=0; i < cp->NumberOfCommands; ++i) + { + if(!kwsysProcessCreate(cp, i, &si, &readEnd)) + { + failed = 1; + } + + /* Set the output pipe of the last process to be non-blocking in + case select lies, or for the polling implementation. */ + if(i == (cp->NumberOfCommands-1) && !kwsysProcessSetNonBlocking(readEnd)) + { + failed = 1; + } + + if(failed) + { + kwsysProcessCleanup(cp, 1); + + /* Release resources that may have been allocated for this + process before an error occurred. */ + kwsysProcessCleanupDescriptor(&readEnd); + if(si.StdIn != 0) + { + kwsysProcessCleanupDescriptor(&si.StdIn); + } + if(si.StdOut != 1) + { + kwsysProcessCleanupDescriptor(&si.StdOut); + } + if(si.StdErr != 2) + { + kwsysProcessCleanupDescriptor(&si.StdErr); + } + kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]); + return; + } + } + /* Save a handle to the output pipe for the last process. */ + cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = readEnd; + } + + /* The parent process does not need the output pipe write ends. */ + if(si.StdErr != 2) + { + kwsysProcessCleanupDescriptor(&si.StdErr); + } + + /* 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_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; +} + +/*--------------------------------------------------------------------------*/ +/* Initialize a process control structure for kwsysProcess_Execute. */ +static int kwsysProcessInitialize(kwsysProcess* cp) +{ + int i; + for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) + { + cp->PipeReadEnds[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"); + + if(cp->ForkPIDs) + { + free(cp->ForkPIDs); + } + cp->ForkPIDs = (pid_t*)malloc(sizeof(pid_t)*(size_t)(cp->NumberOfCommands)); + if(!cp->ForkPIDs) + { + return 0; + } + memset(cp->ForkPIDs, 0, sizeof(pid_t)*(size_t)(cp->NumberOfCommands)); + + 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 = + 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) + { + free(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]); + } +} + +/*--------------------------------------------------------------------------*/ +/* Close the given file descriptor if it is open. Reset its value to -1. */ +static void kwsysProcessCleanupDescriptor(int* pfd) +{ + if(pfd && *pfd >= 0) + { + /* 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, int* readEnd) +{ + /* Setup the process's stdin. */ + if(prIndex > 0) + { + si->StdIn = *readEnd; + *readEnd = 0; + } + else if(cp->PipeFileSTDIN) + { + /* Open a file for the child's stdin to read. */ + si->StdIn = open(cp->PipeFileSTDIN, O_RDONLY); + if(si->StdIn < 0) + { + return 0; + } + + /* Set close-on-exec flag on the pipe's end. */ + if(fcntl(si->StdIn, F_SETFD, FD_CLOEXEC) < 0) + { + return 0; + } + } + else if(cp->PipeSharedSTDIN) + { + si->StdIn = 0; + } + else if(cp->PipeNativeSTDIN[0] >= 0) + { + si->StdIn = 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)) + { + return 0; + } + } + else + { + si->StdIn = -1; + } + + /* Setup the process's stdout. */ + { + /* Create the pipe. */ + int p[2]; + if(pipe(p KWSYSPE_VMS_NONBLOCK) < 0) + { + return 0; + } + *readEnd = p[0]; + si->StdOut = 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)) + { + return 0; + } + } + + /* Replace the stdout pipe with a file if requested. In this case + the select call will report that stdout is closed immediately. */ + if(prIndex == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT) + { + if(!kwsysProcessSetupOutputPipeFile(&si->StdOut, cp->PipeFileSTDOUT)) + { + return 0; + } + } + + /* Replace the stdout pipe with the parent's if requested. In this + case the select call will report that stderr is closed + immediately. */ + if(prIndex == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT) + { + kwsysProcessCleanupDescriptor(&si->StdOut); + si->StdOut = 1; + } + + /* Replace the stdout pipe with the native pipe provided if any. In + this case the select call will report that stdout is closed + immediately. */ + if(prIndex == cp->NumberOfCommands-1 && cp->PipeNativeSTDOUT[1] >= 0) + { + if(!kwsysProcessSetupOutputPipeNative(&si->StdOut, cp->PipeNativeSTDOUT)) + { + return 0; + } + } + + /* Create the error reporting pipe. */ + if(pipe(si->ErrorPipe) < 0) + { + return 0; + } + + /* Set close-on-exec flag on the error pipe's write end. */ + if(fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0) + { + 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. */ + cp->ForkPIDs[prIndex] = vfork(); +#else + cp->ForkPIDs[prIndex] = kwsysProcessFork(cp, si); +#endif + if(cp->ForkPIDs[prIndex] < 0) + { + 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 pipe. */ + close(si->ErrorPipe[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(); +#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? */ + + /* 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 + + /* A child has been created. */ + ++cp->CommandsLeft; + + /* We are done with the error reporting pipe write end. */ + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + + /* 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; + } + } + + /* Successfully created this child process. */ + if(prIndex > 0 || si->StdIn > 0) + { + /* The parent process does not need the input pipe read end. */ + kwsysProcessCleanupDescriptor(&si->StdIn); + } + + /* The parent process does not need the output pipe write ends. */ + if(si->StdOut != 1) + { + kwsysProcessCleanupDescriptor(&si->StdOut); + } + + return 1; +} + +/*--------------------------------------------------------------------------*/ +static void kwsysProcessDestroy(kwsysProcess* cp) +{ + /* A child process has terminated. Reap it if it is one handled by + this object. */ + int i; + 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; + } + } + } +} + +/*--------------------------------------------------------------------------*/ +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(¤t_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); + + /* 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); + 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); + } + } + } + fclose(f); + } + } + } + } + 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 handler. */ +static struct sigaction kwsysProcessesOldSigChldAction; + +/*--------------------------------------------------------------------------*/ +static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses) +{ + /* Block SIGCHLD 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); + 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 newSigChldAction; + memset(&newSigChldAction, 0, sizeof(struct sigaction)); +#if KWSYSPE_USE_SIGINFO + newSigChldAction.sa_sigaction = kwsysProcessesSignalHandler; + newSigChldAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; +# ifdef SA_RESTART + newSigChldAction.sa_flags |= SA_RESTART; +# endif +#else + newSigChldAction.sa_handler = kwsysProcessesSignalHandler; + newSigChldAction.sa_flags = SA_NOCLDSTOP; +#endif + while((sigaction(SIGCHLD, &newSigChldAction, + &kwsysProcessesOldSigChldAction) < 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 SIGCHLD handler. Repeat call until it is not + interrupted. */ + while((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 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 + ) +{ + (void)signum; +#if KWSYSPE_USE_SIGINFO + (void)info; + (void)ucontext; +#endif + + /* Signal all process objects that a child has terminated. */ + { + int i; + 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 status= + read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1); + status=write(cp->SignalPipe, &buf, 1); + (void)status; + } + } + +#if !KWSYSPE_USE_SIGINFO + /* Re-Install our handler for SIGCHLD. Repeat call until it is not + interrupted. */ + { + struct sigaction newSigChldAction; + memset(&newSigChldAction, 0, sizeof(struct sigaction)); + newSigChldAction.sa_handler = kwsysProcessesSignalHandler; + newSigChldAction.sa_flags = SA_NOCLDSTOP; + while((sigaction(SIGCHLD, &newSigChldAction, + &kwsysProcessesOldSigChldAction) < 0) && + (errno == EINTR)); + } +#endif +} diff --git a/ProcessWin32.c b/ProcessWin32.c new file mode 100644 index 000000000..5aa4d8bf6 --- /dev/null +++ b/ProcessWin32.c @@ -0,0 +1,2952 @@ +/*============================================================================ + 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 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. + +On Windows9x platforms, a small WIN32 console application is spawned +in-between the calling process and the actual child to be executed. +This is to work-around a problem with connecting pipes from WIN16 +console applications to WIN32 applications. + +For more information, please check Microsoft Knowledge Base Articles +Q190351 and Q150956. + +*/ + +#ifdef _MSC_VER +#pragma warning (push, 1) +#endif +#include /* Windows API */ +#include /* strlen, strdup */ +#include /* sprintf */ +#include /* _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 + +#define kwsysEncodedWriteArrayProcessFwd9x kwsys_ns(EncodedWriteArrayProcessFwd9x) + +typedef LARGE_INTEGER kwsysProcessTime; + +typedef struct kwsysProcessCreateInformation_s +{ + /* Windows child startup control data. */ + STARTUPINFO StartupInfo; + + /* Special error reporting pipe for Win9x forwarding executable. */ + HANDLE ErrorPipeRead; + HANDLE ErrorPipeWrite; +} 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 int kwsysProcessCreate(kwsysProcess* cp, int index, + kwsysProcessCreateInformation* si, + PHANDLE readEnd); +static void kwsysProcessDestroy(kwsysProcess* cp, int event); +static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name); +static int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle); +static int kwsysProcessSetupPipeNative(PHANDLE handle, HANDLE p[2], + int isWrite); +static void kwsysProcessCleanupHandle(PHANDLE h); +static void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle); +static void kwsysProcessCleanup(kwsysProcess* cp, int error); +static void kwsysProcessCleanErrorMessage(kwsysProcess* cp); +static int kwsysProcessComputeCommandLength(kwsysProcess* cp, + char const* const* command); +static void kwsysProcessComputeCommandLine(kwsysProcess* cp, + char const* const* command, + char* cmd); +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); +extern kwsysEXPORT int kwsysEncodedWriteArrayProcessFwd9x(const char* fname); + +/*--------------------------------------------------------------------------*/ +/* 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. */ + char** Commands; + int NumberOfCommands; + + /* The exit code of each command. */ + DWORD* CommandExitCodes; + + /* The working directory for the child 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 hide the child process's window. */ + int HideWindow; + + /* Whether to treat command lines as verbatim. */ + int Verbatim; + + /* On Win9x platforms, the path to the forwarding executable. */ + char* Win9x; + + /* On Win9x platforms, the resume event for the forwarding executable. */ + HANDLE Win9xResumeEvent; + + /* On Win9x platforms, the kill event for the forwarding executable. */ + HANDLE Win9xKillEvent; + + /* 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]; + + /* Handle to automatically delete the Win9x forwarding executable. */ + HANDLE Win9xHandle; + + /* ------------- 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 (possibly from Win9x child). */ + 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; + char* RealWorkingDirectory; +}; + +/*--------------------------------------------------------------------------*/ +kwsysProcess* kwsysProcess_New(void) +{ + int i; + + /* Process control structure. */ + kwsysProcess* cp; + + /* Path to Win9x forwarding executable. */ + char* win9x = 0; + + /* Windows version number data. */ + OSVERSIONINFO osv; + + /* 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); + GetVersionEx(&osv); + if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + /* This is Win9x. We need the console forwarding executable to + work-around a Windows 9x bug. */ + char fwdName[_MAX_FNAME+1] = ""; + char tempDir[_MAX_PATH+1] = ""; + + /* We will try putting the executable in the system temp + directory. Note that the returned path already has a trailing + slash. */ + DWORD length = GetTempPath(_MAX_PATH+1, tempDir); + + /* Construct the executable name from the process id and kwsysProcess + instance. This should be unique. */ + sprintf(fwdName, KWSYS_NAMESPACE_STRING "pew9xfwd_%ld_%p.exe", + GetCurrentProcessId(), cp); + + /* If we have a temp directory, use it. */ + if(length > 0 && length <= _MAX_PATH) + { + /* Allocate a buffer to hold the forwarding executable path. */ + size_t tdlen = strlen(tempDir); + win9x = (char*)malloc(tdlen + strlen(fwdName) + 2); + if(!win9x) + { + kwsysProcess_Delete(cp); + return 0; + } + + /* Construct the full path to the forwarding executable. */ + sprintf(win9x, "%s%s", tempDir, fwdName); + } + + /* If we found a place to put the forwarding executable, try to + write it. */ + if(win9x) + { + if(!kwsysEncodedWriteArrayProcessFwd9x(win9x)) + { + /* Failed to create forwarding executable. Give up. */ + free(win9x); + kwsysProcess_Delete(cp); + return 0; + } + + /* Get a handle to the file that will delete it when closed. */ + cp->Win9xHandle = CreateFile(win9x, GENERIC_READ, FILE_SHARE_READ, 0, + OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0); + if(cp->Win9xHandle == INVALID_HANDLE_VALUE) + { + /* We were not able to get a read handle for the forwarding + executable. It will not be deleted properly. Give up. */ + _unlink(win9x); + free(win9x); + kwsysProcess_Delete(cp); + return 0; + } + } + else + { + /* Failed to find a place to put forwarding executable. */ + kwsysProcess_Delete(cp); + return 0; + } + } + + /* Save the path to the forwarding executable. */ + cp->Win9x = win9x; + + /* 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; + } + + if(cp->Win9x) + { + SECURITY_ATTRIBUTES sa; + ZeroMemory(&sa, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + /* Create an event to tell the forwarding executable to resume the + child. */ + if(!(cp->Win9xResumeEvent = CreateEvent(&sa, TRUE, 0, 0))) + { + kwsysProcess_Delete(cp); + return 0; + } + + /* Create an event to tell the forwarding executable to kill the + child. */ + if(!(cp->Win9xKillEvent = CreateEvent(&sa, TRUE, 0, 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; + } + } + + 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); + + /* Close the Win9x resume and kill event handles. */ + if(cp->Win9x) + { + kwsysProcessCleanupHandle(&cp->Win9xResumeEvent); + kwsysProcessCleanupHandle(&cp->Win9xKillEvent); + } + + /* 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); + } + if(cp->Win9x) + { + /* Close our handle to the forwarding executable file. This will + cause it to be deleted. */ + kwsysProcessCleanupHandle(&cp->Win9xHandle); + } + 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; + 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*) * 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]; + } + } + + /* We need to construct a single string representing the command + and its arguments. We will surround each argument containing + spaces with double-quotes. Inside a double-quoted argument, we + need to escape double-quotes and all backslashes before them. + We also need to escape backslashes at the end of an argument + because they come before the closing double-quote for the + argument. */ + { + /* First determine the length of the final string. */ + int length = kwsysProcessComputeCommandLength(cp, command); + + /* Allocate enough space for the command. We do not need an extra + byte for the terminating null because we allocated a space for + the first argument that we will not use. */ + newCommands[cp->NumberOfCommands] = (char*)malloc(length); + if(!newCommands[cp->NumberOfCommands]) + { + /* Out of memory. */ + free(newCommands); + return 0; + } + + /* Construct the command line in the allocated buffer. */ + kwsysProcessComputeCommandLine(cp, command, + newCommands[cp->NumberOfCommands]); + } + + /* 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; + } +} + +/*--------------------------------------------------------------------------*/ +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]) + { + /* We must convert the working directory to a full path. */ + DWORD length = GetFullPathName(dir, 0, 0, 0); + if(length > 0) + { + cp->WorkingDirectory = (char*)malloc(length); + if(!cp->WorkingDirectory) + { + return 0; + } + if(!GetFullPathName(dir, length, cp->WorkingDirectory, 0)) + { + free(cp->WorkingDirectory); + cp->WorkingDirectory = 0; + return 0; + } + } + } + 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_Verbatim: return cp->Verbatim; + 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_Verbatim: cp->Verbatim = 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; + + /* Child startup control data. */ + kwsysProcessCreateInformation si; + + /* 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(!GetCurrentDirectory(cp->RealWorkingDirectoryLength, + cp->RealWorkingDirectory)) + { + kwsysProcessCleanup(cp, 1); + return; + } + SetCurrentDirectory(cp->WorkingDirectory); + } + + /* Reset the Win9x resume and kill events. */ + if(cp->Win9x) + { + if(!ResetEvent(cp->Win9xResumeEvent)) + { + kwsysProcessCleanup(cp, 1); + return; + } + if(!ResetEvent(cp->Win9xKillEvent)) + { + kwsysProcessCleanup(cp, 1); + return; + } + } + + /* 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; + + /* Create stderr pipe to be shared by all processes in the pipeline. + Neither end is directly inherited. */ + if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read, + &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) + { + kwsysProcessCleanup(cp, 1); + return; + } + + /* Create an inherited duplicate of the write end, but do not + close the non-inherited version. We need to keep it open + to use in waking up the pipe threads. */ + if(!DuplicateHandle(GetCurrentProcess(), cp->Pipe[KWSYSPE_PIPE_STDERR].Write, + GetCurrentProcess(), &si.StartupInfo.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupHandle(&si.StartupInfo.hStdError); + return; + } + + /* Replace the stderr pipe with a file if requested. In this case + the pipe thread will still run but never report data. */ + if(cp->PipeFileSTDERR) + { + if(!kwsysProcessSetupOutputPipeFile(&si.StartupInfo.hStdError, + cp->PipeFileSTDERR)) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupHandle(&si.StartupInfo.hStdError); + return; + } + } + + /* Replace the stderr pipe with the parent process's if requested. + In this case the pipe thread will still run but never report + data. */ + if(cp->PipeSharedSTDERR) + { + if(!kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, + &si.StartupInfo.hStdError)) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, + STD_ERROR_HANDLE); + return; + } + } + + /* Replace the stderr pipe with the native pipe provided if any. In + this case the pipe thread will still run but never report + data. */ + if(cp->PipeNativeSTDERR[1]) + { + if(!kwsysProcessSetupPipeNative(&si.StartupInfo.hStdError, + cp->PipeNativeSTDERR, 1)) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, + STD_ERROR_HANDLE); + return; + } + } + + /* Create the pipeline of processes. */ + { + HANDLE readEnd = 0; + for(i=0; i < cp->NumberOfCommands; ++i) + { + if(kwsysProcessCreate(cp, i, &si, &readEnd)) + { + cp->ProcessEvents[i+1] = cp->ProcessInformation[i].hProcess; + } + else + { + kwsysProcessCleanup(cp, 1); + + /* Release resources that may have been allocated for this + process before an error occurred. */ + kwsysProcessCleanupHandle(&readEnd); + kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdInput, + STD_INPUT_HANDLE); + kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdOutput, + STD_OUTPUT_HANDLE); + kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, + STD_ERROR_HANDLE); + kwsysProcessCleanupHandle(&si.ErrorPipeRead); + kwsysProcessCleanupHandle(&si.ErrorPipeWrite); + return; + } + } + + /* Save a handle to the output pipe for the last process. */ + cp->Pipe[KWSYSPE_PIPE_STDOUT].Read = readEnd; + } + + /* Close the inherited handles to the stderr pipe shared by all + processes in the pipeline. The stdout and stdin pipes are not + shared among all children and are therefore closed by + kwsysProcessCreate after each child is created. */ + kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, STD_ERROR_HANDLE); + + /* Restore the working directory. */ + if(cp->RealWorkingDirectory) + { + SetCurrentDirectory(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. */ + if(cp->Win9x) + { + SetEvent(cp->Win9xResumeEvent); + } + else + { + 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_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; + if(cp->Win9x) + { + /* Windows 9x. Tell the forwarding executable to kill the child. */ + SetEvent(cp->Win9xKillEvent); + } + else + { + /* Not Windows 9x. Just terminate the children. */ + for(i=0; i < cp->NumberOfCommands; ++i) + { + kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId); + // close the handle if we kill it + 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 = GetCurrentDirectory(0, 0); + if(cp->RealWorkingDirectoryLength > 0) + { + cp->RealWorkingDirectory = (char*)malloc(cp->RealWorkingDirectoryLength); + if(!cp->RealWorkingDirectory) + { + return 0; + } + } + } + + return 1; +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcessCreate(kwsysProcess* cp, int index, + kwsysProcessCreateInformation* si, + PHANDLE readEnd) +{ + /* Setup the process's stdin. */ + if(*readEnd) + { + /* Create an inherited duplicate of the read end from the output + pipe of the previous process. This also closes the + non-inherited version. */ + if(!DuplicateHandle(GetCurrentProcess(), *readEnd, + GetCurrentProcess(), readEnd, + 0, TRUE, (DUPLICATE_CLOSE_SOURCE | + DUPLICATE_SAME_ACCESS))) + { + return 0; + } + si->StartupInfo.hStdInput = *readEnd; + + /* This function is done with this handle. */ + *readEnd = 0; + } + else if(cp->PipeFileSTDIN) + { + /* Create a handle to read a file for stdin. */ + HANDLE fin = CreateFile(cp->PipeFileSTDIN, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + 0, OPEN_EXISTING, 0, 0); + if(fin == INVALID_HANDLE_VALUE) + { + return 0; + } + /* Create an inherited duplicate of the handle. This also closes + the non-inherited version. */ + if(!DuplicateHandle(GetCurrentProcess(), fin, + GetCurrentProcess(), &fin, + 0, TRUE, (DUPLICATE_CLOSE_SOURCE | + DUPLICATE_SAME_ACCESS))) + { + return 0; + } + si->StartupInfo.hStdInput = fin; + } + else if(cp->PipeSharedSTDIN) + { + /* Share this process's stdin with the child. */ + if(!kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, + &si->StartupInfo.hStdInput)) + { + return 0; + } + } + else if(cp->PipeNativeSTDIN[0]) + { + /* Use the provided native pipe. */ + if(!kwsysProcessSetupPipeNative(&si->StartupInfo.hStdInput, + cp->PipeNativeSTDIN, 0)) + { + return 0; + } + } + else + { + /* Explicitly give the child no stdin. */ + si->StartupInfo.hStdInput = INVALID_HANDLE_VALUE; + } + + /* Setup the process's stdout. */ + { + DWORD maybeClose = DUPLICATE_CLOSE_SOURCE; + HANDLE writeEnd; + + /* Create the output pipe for this process. Neither end is directly + inherited. */ + if(!CreatePipe(readEnd, &writeEnd, 0, 0)) + { + return 0; + } + + /* Create an inherited duplicate of the write end. Close the + non-inherited version unless this is the last process. Save the + non-inherited write end of the last process. */ + if(index == cp->NumberOfCommands-1) + { + cp->Pipe[KWSYSPE_PIPE_STDOUT].Write = writeEnd; + maybeClose = 0; + } + if(!DuplicateHandle(GetCurrentProcess(), writeEnd, + GetCurrentProcess(), &writeEnd, + 0, TRUE, (maybeClose | DUPLICATE_SAME_ACCESS))) + { + return 0; + } + si->StartupInfo.hStdOutput = writeEnd; + } + + /* Replace the stdout pipe with a file if requested. In this case + the pipe thread will still run but never report data. */ + if(index == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT) + { + if(!kwsysProcessSetupOutputPipeFile(&si->StartupInfo.hStdOutput, + cp->PipeFileSTDOUT)) + { + return 0; + } + } + + /* Replace the stdout pipe of the last child with the parent + process's if requested. In this case the pipe thread will still + run but never report data. */ + if(index == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT) + { + if(!kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, + &si->StartupInfo.hStdOutput)) + { + return 0; + } + } + + /* Replace the stdout pipe with the native pipe provided if any. In + this case the pipe thread will still run but never report + data. */ + if(index == cp->NumberOfCommands-1 && cp->PipeNativeSTDOUT[1]) + { + if(!kwsysProcessSetupPipeNative(&si->StartupInfo.hStdOutput, + cp->PipeNativeSTDOUT, 1)) + { + return 0; + } + } + + /* Create the child process. */ + { + BOOL r; + char* realCommand; + if(cp->Win9x) + { + /* Create an error reporting pipe for the forwarding executable. + Neither end is directly inherited. */ + if(!CreatePipe(&si->ErrorPipeRead, &si->ErrorPipeWrite, 0, 0)) + { + return 0; + } + + /* Create an inherited duplicate of the write end. This also closes + the non-inherited version. */ + if(!DuplicateHandle(GetCurrentProcess(), si->ErrorPipeWrite, + GetCurrentProcess(), &si->ErrorPipeWrite, + 0, TRUE, (DUPLICATE_CLOSE_SOURCE | + DUPLICATE_SAME_ACCESS))) + { + return 0; + } + + /* The forwarding executable is given a handle to the error pipe + and resume and kill events. */ + realCommand = (char*)malloc(strlen(cp->Win9x)+strlen(cp->Commands[index])+100); + if(!realCommand) + { + return 0; + } + sprintf(realCommand, "%s %p %p %p %d %s", cp->Win9x, + si->ErrorPipeWrite, cp->Win9xResumeEvent, cp->Win9xKillEvent, + cp->HideWindow, cp->Commands[index]); + } + else + { + realCommand = cp->Commands[index]; + } + + /* Create the child in a suspended state so we can wait until all + children have been created before running any one. */ + r = CreateProcess(0, realCommand, 0, 0, TRUE, + cp->Win9x? 0 : CREATE_SUSPENDED, 0, 0, + &si->StartupInfo, &cp->ProcessInformation[index]); + if(cp->Win9x) + { + /* Free memory. */ + free(realCommand); + + /* Close the error pipe write end so we can detect when the + forwarding executable closes it. */ + kwsysProcessCleanupHandle(&si->ErrorPipeWrite); + if(r) + { + /* Wait for the forwarding executable to report an error or + close the error pipe to report success. */ + DWORD total = 0; + DWORD n = 1; + while(total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0) + { + if(ReadFile(si->ErrorPipeRead, cp->ErrorMessage+total, + KWSYSPE_PIPE_BUFFER_SIZE-total, &n, 0)) + { + total += n; + } + else + { + n = 0; + } + } + if(total > 0 || GetLastError() != ERROR_BROKEN_PIPE) + { + /* The forwarding executable could not run the process, or + there was an error reading from its error pipe. Preserve + the last error while cleaning up the forwarding executable + so the cleanup our caller does reports the proper error. */ + DWORD error = GetLastError(); + kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread); + kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); + SetLastError(error); + return 0; + } + } + kwsysProcessCleanupHandle(&si->ErrorPipeRead); + } + + if(!r) + { + return 0; + } + } + + /* Successfully created this child process. Close the current + process's copies of the inherited stdout and stdin handles. The + stderr handle is shared among all children and is closed by + kwsysProcess_Execute after all children have been created. */ + kwsysProcessCleanupHandleSafe(&si->StartupInfo.hStdInput, + STD_INPUT_HANDLE); + kwsysProcessCleanupHandleSafe(&si->StartupInfo.hStdOutput, + STD_OUTPUT_HANDLE); + + return 1; +} + +/*--------------------------------------------------------------------------*/ +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]); + + /* 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); + } + } +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name) +{ + HANDLE fout; + if(!name) + { + return 1; + } + + /* Close the existing inherited handle. */ + kwsysProcessCleanupHandle(phandle); + + /* Create a handle to write a file for the pipe. */ + fout = CreateFile(name, GENERIC_WRITE, FILE_SHARE_READ, 0, + CREATE_ALWAYS, 0, 0); + if(fout == INVALID_HANDLE_VALUE) + { + return 0; + } + + /* Create an inherited duplicate of the handle. This also closes + the non-inherited version. */ + if(!DuplicateHandle(GetCurrentProcess(), fout, + GetCurrentProcess(), &fout, + 0, TRUE, (DUPLICATE_CLOSE_SOURCE | + DUPLICATE_SAME_ACCESS))) + { + return 0; + } + + /* Assign the replacement handle. */ + *phandle = fout; + return 1; +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle) +{ + /* Check whether the handle to be shared is already inherited. */ + DWORD flags; + int inherited = 0; + if(GetHandleInformation(GetStdHandle(nStdHandle), &flags) && + (flags & HANDLE_FLAG_INHERIT)) + { + inherited = 1; + } + + /* Cleanup the previous handle. */ + kwsysProcessCleanupHandle(handle); + + /* If the standard handle is not inherited then duplicate it to + create an inherited copy. Do not close the original handle when + duplicating! */ + if(inherited) + { + *handle = GetStdHandle(nStdHandle); + return 1; + } + else if(DuplicateHandle(GetCurrentProcess(), GetStdHandle(nStdHandle), + GetCurrentProcess(), handle, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + return 1; + } + else + { + /* The given standard handle is not valid for this process. Some + child processes may break if they do not have a valid standard + pipe, so give the child an empty pipe. For the stdin pipe we + want to close the write end and give the read end to the child. + For stdout and stderr we want to close the read end and give + the write end to the child. */ + int child_end = (nStdHandle == STD_INPUT_HANDLE)? 0:1; + int parent_end = (nStdHandle == STD_INPUT_HANDLE)? 1:0; + HANDLE emptyPipe[2]; + if(!CreatePipe(&emptyPipe[0], &emptyPipe[1], 0, 0)) + { + return 0; + } + + /* Close the non-inherited end so the pipe will be broken + immediately. */ + CloseHandle(emptyPipe[parent_end]); + + /* Create an inherited duplicate of the handle. This also + closes the non-inherited version. */ + if(!DuplicateHandle(GetCurrentProcess(), emptyPipe[child_end], + GetCurrentProcess(), &emptyPipe[child_end], + 0, TRUE, (DUPLICATE_CLOSE_SOURCE | + DUPLICATE_SAME_ACCESS))) + { + return 0; + } + + /* Give the inherited handle to the child. */ + *handle = emptyPipe[child_end]; + return 1; + } +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcessSetupPipeNative(PHANDLE handle, HANDLE p[2], int isWrite) +{ + /* Close the existing inherited handle. */ + kwsysProcessCleanupHandle(handle); + + /* Create an inherited duplicate of the handle. This also closes + the non-inherited version. */ + if(!DuplicateHandle(GetCurrentProcess(), p[isWrite? 1:0], + GetCurrentProcess(), handle, + 0, TRUE, (DUPLICATE_CLOSE_SOURCE | + DUPLICATE_SAME_ACCESS))) + { + return 0; + } + + return 1; +} + +/*--------------------------------------------------------------------------*/ + +/* Close the given handle if it is open. Reset its value to 0. */ +void kwsysProcessCleanupHandle(PHANDLE h) +{ + if(h && *h) + { + CloseHandle(*h); + *h = 0; + } +} + +/*--------------------------------------------------------------------------*/ + +/* Close the given handle if it is open and not a standard handle. + Reset its value to 0. */ +void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle) +{ + if(h && *h && (*h != GetStdHandle(nStdHandle))) + { + CloseHandle(*h); + *h = 0; + } +} + +/*--------------------------------------------------------------------------*/ + +/* Close all handles created by kwsysProcess_Execute. */ +void kwsysProcessCleanup(kwsysProcess* cp, int 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. */ + DWORD original = GetLastError(); + DWORD length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, 0, original, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + cp->ErrorMessage, 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", + original, 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) + { + if(cp->Win9x) + { + SetEvent(cp->Win9xKillEvent); + } + else + { + 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) + { + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); + } + } + + /* Restore the working directory. */ + if(cp->RealWorkingDirectory) + { + SetCurrentDirectory(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; + } +} + +/*--------------------------------------------------------------------------*/ +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; + } +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcessComputeCommandLength(kwsysProcess* cp, + char const* const* command) +{ + int length = 0; + if(cp->Verbatim) + { + /* Treat the first argument as a verbatim command line. Use its + length directly and add space for the null-terminator. */ + length = (int)strlen(*command)+1; + } + else + { + /* Compute the length of the command line when it is converted to + a single string. Space for the null-terminator is allocated by + the whitespace character allocated for the first argument that + will not be used. */ + char const* const* arg; + for(arg = command; *arg; ++arg) + { + /* Add the length of this argument. It already includes room + for a separating space or terminating null. */ + length += kwsysSystem_Shell_GetArgumentSizeForWindows(*arg, 0); + } + } + + return length; +} + +/*--------------------------------------------------------------------------*/ +void kwsysProcessComputeCommandLine(kwsysProcess* cp, + char const* const* command, + char* cmd) +{ + if(cp->Verbatim) + { + /* Copy the verbatim command line into the buffer. */ + strcpy(cmd, *command); + } + else + { + /* Construct the command line in the allocated buffer. */ + char const* const* arg; + for(arg = command; *arg; ++arg) + { + /* Add the separating space if this is not the first argument. */ + if(arg != command) + { + *cmd++ = ' '; + } + + /* Add the current argument. */ + cmd = kwsysSystem_Shell_GetArgumentForWindows(*arg, cmd, 0); + } + + /* Add the terminating null character to the command line. */ + *cmd = 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; + sprintf(cp->ExitExceptionString, "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); + GetVersionEx(&osv); + 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 = GetModuleHandle("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 = GetModuleHandle("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); + } +} diff --git a/README.txt b/README.txt new file mode 100644 index 000000000..ba03f8dde --- /dev/null +++ b/README.txt @@ -0,0 +1,10 @@ +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. diff --git a/Registry.cxx b/Registry.cxx new file mode 100644 index 000000000..cd521c966 --- /dev/null +++ b/Registry.cxx @@ -0,0 +1,818 @@ +/*============================================================================ + 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(Registry.hxx) + +#include KWSYS_HEADER(Configure.hxx) +#include KWSYS_HEADER(ios/iostream) +#include KWSYS_HEADER(stl/string) +#include KWSYS_HEADER(stl/map) +#include KWSYS_HEADER(ios/iostream) +#include KWSYS_HEADER(ios/fstream) +#include KWSYS_HEADER(ios/sstream) +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Registry.hxx.in" +# include "Configure.hxx.in" +# include "kwsys_stl.hxx.in" +# include "kwsys_stl_string.hxx.in" +# include "kwsys_stl_map.hxx.in" +# include "kwsys_ios_iostream.h.in" +# include "kwsys_ios_fstream.h.in" +# include "kwsys_ios_sstream.h.in" +#endif + +#include // for isspace +#include +#include /* strlen, strncpy */ +#include /* getenv */ + +#ifdef _WIN32 +# include +#endif + + +namespace KWSYS_NAMESPACE +{ +class RegistryHelper { +public: + RegistryHelper(Registry::RegistryType registryType); + virtual ~RegistryHelper(); + + // Read a value from the registry. + virtual bool ReadValue(const char *key, const char **value); + + // Delete a key from the registry. + virtual bool DeleteKey(const char *key); + + // Delete a value from a given key. + virtual bool DeleteValue(const char *key); + + // Set value in a given key. + virtual bool SetValue(const char *key, const char *value); + + // Open the registry at toplevel/subkey. + virtual bool Open(const char *toplevel, const char *subkey, + int readonly); + + // Close the registry. + virtual bool Close(); + + // Set the value of changed + void SetChanged(bool b) { m_Changed = b; } + void SetTopLevel(const char* tl); + const char* GetTopLevel() { return m_TopLevel.c_str(); } + + //! Read from local or global scope. On Windows this mean from local machine + // or local user. On unix this will read from $HOME/.Projectrc or + // /etc/Project + void SetGlobalScope(bool b); + bool GetGlobalScope(); + + kwsys_stl::string EncodeKey(const char* str); + kwsys_stl::string EncodeValue(const char* str); + kwsys_stl::string DecodeValue(const char* str); + +protected: + bool m_Changed; + kwsys_stl::string m_TopLevel; + bool m_GlobalScope; + +#ifdef _WIN32 + HKEY HKey; +#endif + // Strip trailing and ending spaces. + char *Strip(char *str); + void SetSubKey(const char* sk); + kwsys_stl::string CreateKey(const char *key); + + typedef kwsys_stl::map StringToStringMap; + StringToStringMap EntriesMap; + kwsys_stl::string m_SubKey; + bool m_Empty; + bool m_SubKeySpecified; + kwsys_stl::string m_HomeDirectory; + + Registry::RegistryType m_RegistryType; +}; + +//---------------------------------------------------------------------------- +#define Registry_BUFFER_SIZE 8192 + +//---------------------------------------------------------------------------- +Registry::Registry(Registry::RegistryType registryType) +{ + m_Opened = false; + m_Locked = false; + this->Helper = 0; + this->Helper = new RegistryHelper(registryType); +} + +//---------------------------------------------------------------------------- +Registry::~Registry() +{ + if ( m_Opened ) + { + kwsys_ios::cerr << "Registry::Close should be " + "called here. The registry is not closed." + << kwsys_ios::endl; + } + delete this->Helper; +} + +//---------------------------------------------------------------------------- +void Registry::SetGlobalScope(bool b) +{ + this->Helper->SetGlobalScope(b); +} + +//---------------------------------------------------------------------------- +bool Registry::GetGlobalScope() +{ + return this->Helper->GetGlobalScope(); +} + +//---------------------------------------------------------------------------- +bool Registry::Open(const char *toplevel, + const char *subkey, int readonly) +{ + bool res = false; + if ( m_Locked ) + { + return res; + } + if ( m_Opened ) + { + if ( !this->Close() ) + { + return res; + } + } + if ( !toplevel || !*toplevel ) + { + kwsys_ios::cerr << "Registry::Opened() Toplevel not defined" + << kwsys_ios::endl; + return res; + } + + if ( isspace(toplevel[0]) || + isspace(toplevel[strlen(toplevel)-1]) ) + { + kwsys_ios::cerr << "Toplevel has to start with letter or number and end" + " with one" << kwsys_ios::endl; + return res; + } + + res = this->Helper->Open(toplevel, subkey, readonly); + if ( readonly != Registry::READONLY ) + { + m_Locked = true; + } + + if ( res ) + { + m_Opened = true; + this->Helper->SetTopLevel(toplevel); + } + return res; +} + +//---------------------------------------------------------------------------- +bool Registry::Close() +{ + bool res = false; + if ( m_Opened ) + { + res = this->Helper->Close(); + } + + if ( res ) + { + m_Opened = false; + m_Locked = false; + this->Helper->SetChanged(false); + } + return res; +} + +//---------------------------------------------------------------------------- +bool Registry::ReadValue(const char *subkey, + const char *key, + const char **value) +{ + bool res = false; + bool open = false; + if ( ! value ) + { + return res; + } + *value = 0; + if ( !m_Opened ) + { + if ( !this->Open(this->GetTopLevel(), subkey, + Registry::READONLY) ) + { + return res; + } + open = true; + } + res = this->Helper->ReadValue(key, value); + + if ( open ) + { + if ( !this->Close() ) + { + res = false; + } + } + return res; +} + +//---------------------------------------------------------------------------- +bool Registry::DeleteKey(const char *subkey, const char *key) +{ + bool res = false; + bool open = false; + if ( !m_Opened ) + { + if ( !this->Open(this->GetTopLevel(), subkey, + Registry::READWRITE) ) + { + return res; + } + open = true; + } + + res = this->Helper->DeleteKey(key); + if ( res ) + { + this->Helper->SetChanged(true); + } + + if ( open ) + { + if ( !this->Close() ) + { + res = false; + } + } + return res; +} + +//---------------------------------------------------------------------------- +bool Registry::DeleteValue(const char *subkey, const char *key) +{ + bool res = false; + bool open = false; + if ( !m_Opened ) + { + if ( !this->Open(this->GetTopLevel(), subkey, + Registry::READWRITE) ) + { + return res; + } + open = true; + } + + res = this->Helper->DeleteValue(key); + if ( res ) + { + this->Helper->SetChanged(true); + } + + if ( open ) + { + if ( !this->Close() ) + { + res = false; + } + } + return res; +} + +//---------------------------------------------------------------------------- +bool Registry::SetValue(const char *subkey, const char *key, + const char *value) +{ + bool res = false; + bool open = false; + if ( !m_Opened ) + { + if ( !this->Open(this->GetTopLevel(), subkey, + Registry::READWRITE) ) + { + return res; + } + open = true; + } + + res = this->Helper->SetValue( key, value ); + if ( res ) + { + this->Helper->SetChanged(true); + } + + if ( open ) + { + if ( !this->Close() ) + { + res = false; + } + } + return res; +} + +//---------------------------------------------------------------------------- +const char* Registry::GetTopLevel() +{ + return this->Helper->GetTopLevel(); +} + +//---------------------------------------------------------------------------- +void Registry::SetTopLevel(const char* tl) +{ + this->Helper->SetTopLevel(tl); +} + +//---------------------------------------------------------------------------- +void RegistryHelper::SetTopLevel(const char* tl) +{ + if ( tl ) + { + m_TopLevel = tl; + } + else + { + m_TopLevel = ""; + } +} + +//---------------------------------------------------------------------------- +RegistryHelper::RegistryHelper(Registry::RegistryType registryType) +{ + m_Changed = false; + m_TopLevel = ""; + m_SubKey = ""; + m_SubKeySpecified = false; + m_Empty = true; + m_GlobalScope = false; + m_RegistryType = registryType; +} + +//---------------------------------------------------------------------------- +RegistryHelper::~RegistryHelper() +{ +} + + +//---------------------------------------------------------------------------- +bool RegistryHelper::Open(const char *toplevel, const char *subkey, + int readonly) +{ + this->EntriesMap.clear(); + m_Empty = 1; + +#ifdef _WIN32 + if ( m_RegistryType == Registry::WIN32_REGISTRY) + { + HKEY scope = HKEY_CURRENT_USER; + if ( this->GetGlobalScope() ) + { + scope = HKEY_LOCAL_MACHINE; + } + int res = 0; + kwsys_ios::ostringstream str; + DWORD dwDummy; + str << "Software\\Kitware\\" << toplevel << "\\" << subkey; + if ( readonly == Registry::READONLY ) + { + res = ( RegOpenKeyEx(scope, str.str().c_str(), + 0, KEY_READ, &this->HKey) == ERROR_SUCCESS ); + } + else + { + char lpClass[] = ""; + res = ( RegCreateKeyEx(scope, str.str().c_str(), + 0, lpClass, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, + NULL, &this->HKey, &dwDummy) == ERROR_SUCCESS ); + } + if ( res != 0 ) + { + this->SetSubKey( subkey ); + } + return (res != 0); + } +#endif + if ( m_RegistryType == Registry::FILE_REGISTRY ) + { + bool res = false; + int cc; + kwsys_ios::ostringstream str; + const char* homeDirectory; + if ( (homeDirectory = getenv("HOME")) == 0 ) + { + if ( (homeDirectory = getenv("USERPROFILE")) == 0 ) + { + return false; + } + } + m_HomeDirectory = homeDirectory; + str << m_HomeDirectory.c_str() << "/." << toplevel << "rc"; + if ( readonly == Registry::READWRITE ) + { + kwsys_ios::ofstream ofs( str.str().c_str(), kwsys_ios::ios::out|kwsys_ios::ios::app ); + if ( ofs.fail() ) + { + return false; + } + ofs.close(); + } + + kwsys_ios::ifstream *ifs = new kwsys_ios::ifstream(str.str().c_str(), kwsys_ios::ios::in +#ifndef KWSYS_IOS_USE_ANSI + | kwsys_ios::ios::nocreate +#endif + ); + if ( !ifs ) + { + return false; + } + if ( ifs->fail()) + { + delete ifs; + return false; + } + + res = true; + char buffer[Registry_BUFFER_SIZE]; + while( !ifs->fail() ) + { + ifs->getline(buffer, Registry_BUFFER_SIZE); + if ( ifs->fail() || ifs->eof() ) + { + break; + } + char *line = this->Strip(buffer); + if ( *line == '#' || *line == 0 ) + { + // Comment + continue; + } + int linelen = static_cast(strlen(line)); + for ( cc = 0; cc < linelen; cc++ ) + { + if ( line[cc] == '=' ) + { + char *key = new char[ cc+1 ]; + strncpy( key, line, cc ); + key[cc] = 0; + char *value = line + cc + 1; + char *nkey = this->Strip(key); + char *nvalue = this->Strip(value); + this->EntriesMap[nkey] = this->DecodeValue(nvalue); + m_Empty = 0; + delete [] key; + break; + } + } + } + ifs->close(); + this->SetSubKey( subkey ); + delete ifs; + return res; + } + return false; +} + +//---------------------------------------------------------------------------- +bool RegistryHelper::Close() +{ +#ifdef _WIN32 + if ( m_RegistryType == Registry::WIN32_REGISTRY) + { + int res; + res = ( RegCloseKey(this->HKey) == ERROR_SUCCESS ); + return (res != 0); + } +#endif + if ( m_RegistryType == Registry::FILE_REGISTRY ) + { + if ( !m_Changed ) + { + this->SetSubKey(0); + return true; + } + + kwsys_ios::ostringstream str; + str << m_HomeDirectory.c_str() << "/." << this->GetTopLevel() << "rc"; + kwsys_ios::ofstream *ofs = new kwsys_ios::ofstream(str.str().c_str(), kwsys_ios::ios::out); + if ( !ofs ) + { + return false; + } + if ( ofs->fail()) + { + delete ofs; + return false; + } + *ofs << "# This file is automatically generated by the application" << kwsys_ios::endl + << "# If you change any lines or add new lines, note that all" << kwsys_ios::endl + << "# comments and empty lines will be deleted. Every line has" << kwsys_ios::endl + << "# to be in format: " << kwsys_ios::endl + << "# key = value" << kwsys_ios::endl + << "#" << kwsys_ios::endl; + + if ( !this->EntriesMap.empty() ) + { + RegistryHelper::StringToStringMap::iterator it; + for ( it = this->EntriesMap.begin(); + it != this->EntriesMap.end(); + ++ it ) + { + *ofs << it->first.c_str() << " = " << this->EncodeValue(it->second.c_str()).c_str() << kwsys_ios::endl; + } + } + this->EntriesMap.clear(); + ofs->close(); + delete ofs; + this->SetSubKey(0); + m_Empty = 1; + return true; + } + return false; +} + +//---------------------------------------------------------------------------- +bool RegistryHelper::ReadValue(const char *skey, const char **value) + +{ +#ifdef _WIN32 + if ( m_RegistryType == Registry::WIN32_REGISTRY) + { + kwsys_stl::string key = this->CreateKey( skey ); + if ( key.empty() ) + { + return false; + } + DWORD dwType, dwSize; + dwType = REG_SZ; + char buffer[1024]; // Replace with RegQueryInfoKey + dwSize = sizeof(buffer); + int res = ( RegQueryValueEx(this->HKey, skey, NULL, &dwType, + (BYTE *)buffer, &dwSize) == ERROR_SUCCESS ); + if ( !res ) + { + return false; + } + this->EntriesMap[key] = buffer; + RegistryHelper::StringToStringMap::iterator it + = this->EntriesMap.find(key); + *value = it->second.c_str(); + return true; + } +#endif + if ( m_RegistryType == Registry::FILE_REGISTRY ) + { + bool res = false; + kwsys_stl::string key = this->CreateKey( skey ); + if ( key.empty() ) + { + return false; + } + + RegistryHelper::StringToStringMap::iterator it + = this->EntriesMap.find(key); + if ( it != this->EntriesMap.end() ) + { + *value = it->second.c_str(); + res = true; + } + return res; + } + return false; +} + +//---------------------------------------------------------------------------- +bool RegistryHelper::DeleteKey(const char* skey) +{ +#ifdef _WIN32 + if ( m_RegistryType == Registry::WIN32_REGISTRY) + { + int res = ( RegDeleteKey( this->HKey, skey ) == ERROR_SUCCESS ); + return (res != 0); + } +#endif + if ( m_RegistryType == Registry::FILE_REGISTRY ) + { + kwsys_stl::string key = this->CreateKey( skey ); + if ( key.empty() ) + { + return false; + } + this->EntriesMap.erase(key); + return true; + } + return false; +} + +//---------------------------------------------------------------------------- +bool RegistryHelper::DeleteValue(const char *skey) +{ +#ifdef _WIN32 + if ( m_RegistryType == Registry::WIN32_REGISTRY) + { + int res = ( RegDeleteValue( this->HKey, skey ) == ERROR_SUCCESS ); + return (res != 0); + } +#endif + if ( m_RegistryType == Registry::FILE_REGISTRY ) + { + kwsys_stl::string key = this->CreateKey( skey ); + if ( key.empty() ) + { + return false; + } + this->EntriesMap.erase(key); + return true; + } + return false; +} + +//---------------------------------------------------------------------------- +bool RegistryHelper::SetValue(const char *skey, const char *value) +{ +#ifdef _WIN32 + if ( m_RegistryType == Registry::WIN32_REGISTRY) + { + DWORD len = (DWORD)(value ? strlen(value) : 0); + int res = ( RegSetValueEx(this->HKey, skey, 0, REG_SZ, + (CONST BYTE *)(const char *)value, + len+1) == ERROR_SUCCESS ); + return (res != 0); + } +#endif + if ( m_RegistryType == Registry::FILE_REGISTRY ) + { + kwsys_stl::string key = this->CreateKey( skey ); + if ( key.empty() ) + { + return 0; + } + this->EntriesMap[key] = value; + return 1; + } + return false; +} + +//---------------------------------------------------------------------------- +kwsys_stl::string RegistryHelper::CreateKey( const char *key ) +{ + if ( !m_SubKeySpecified || m_SubKey.empty() || !key ) + { + return ""; + } + kwsys_ios::ostringstream ostr; + ostr << this->EncodeKey(this->m_SubKey.c_str()).c_str() + << "\\" << this->EncodeKey(key).c_str(); + return ostr.str(); +} + +//---------------------------------------------------------------------------- +void RegistryHelper::SetSubKey(const char* sk) +{ + if ( !sk ) + { + m_SubKey = ""; + m_SubKeySpecified = false; + } + else + { + m_SubKey = sk; + m_SubKeySpecified = true; + } +} + +//---------------------------------------------------------------------------- +char *RegistryHelper::Strip(char *str) +{ + int cc; + size_t len; + char *nstr; + if ( !str ) + { + return NULL; + } + len = strlen(str); + nstr = str; + for( cc=0; cc < static_cast(len); cc++ ) + { + if ( !isspace( *nstr ) ) + { + break; + } + nstr ++; + } + for( cc= static_cast(strlen(nstr))-1; cc>=0; cc-- ) + { + if ( !isspace( nstr[cc] ) ) + { + nstr[cc+1] = 0; + break; + } + } + return nstr; +} + +//---------------------------------------------------------------------------- +void RegistryHelper::SetGlobalScope(bool b) +{ + m_GlobalScope = b; +} + +//---------------------------------------------------------------------------- +bool RegistryHelper::GetGlobalScope() +{ + return m_GlobalScope; +} + +//---------------------------------------------------------------------------- +kwsys_stl::string RegistryHelper::EncodeKey(const char* str) +{ + kwsys_ios::ostringstream ostr; + while ( *str ) + { + switch ( *str ) + { + case '%': case '=': case '\n': case '\r': case '\t': + char buffer[4]; + sprintf(buffer, "%%%02X", *str); + ostr << buffer; + break; + default: + ostr << *str; + } + str ++; + } + return ostr.str(); +} + +//---------------------------------------------------------------------------- +kwsys_stl::string RegistryHelper::EncodeValue(const char* str) +{ + kwsys_ios::ostringstream ostr; + while ( *str ) + { + switch ( *str ) + { + case '%': case '=': case '\n': case '\r': case '\t': + char buffer[4]; + sprintf(buffer, "%%%02X", *str); + ostr << buffer; + break; + default: + ostr << *str; + } + str ++; + } + return ostr.str(); +} + +//---------------------------------------------------------------------------- +kwsys_stl::string RegistryHelper::DecodeValue(const char* str) +{ + kwsys_ios::ostringstream ostr; + while ( *str ) + { + unsigned int val; + switch ( *str ) + { + case '%': + if ( *(str+1) && *(str+2) && sscanf(str+1, "%x", &val) == 1 ) + { + ostr << static_cast(val); + str += 2; + } + else + { + ostr << *str; + } + break; + default: + ostr << *str; + } + str ++; + } + return ostr.str(); +} + +} // namespace KWSYS_NAMESPACE diff --git a/Registry.hxx.in b/Registry.hxx.in new file mode 100644 index 000000000..ed9b01072 --- /dev/null +++ b/Registry.hxx.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@_Registry_hxx +#define @KWSYS_NAMESPACE@_Registry_hxx + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include <@KWSYS_NAMESPACE@/stl/string> + +namespace @KWSYS_NAMESPACE@ +{ + +class RegistryHelper; + +/** \class Registry + * \brief Portable registry class + * + * This class abstracts the storing of data that can be restored + * when the program executes again. On Win32 platform it is + * implemented using the registry and on unix as a file in + * the user's home directory. + */ +class @KWSYS_NAMESPACE@_EXPORT Registry +{ +public: + enum RegistryType + { +#ifdef _WIN32 + WIN32_REGISTRY, +#endif + FILE_REGISTRY + }; + +#ifdef _WIN32 + Registry(RegistryType registryType = WIN32_REGISTRY); +#else + Registry(RegistryType registryType = FILE_REGISTRY); +#endif + + virtual ~Registry(); + + //! Read a value from the registry. + bool ReadValue(const char *subkey, const char *key, const char **value); + + //! Delete a key from the registry. + bool DeleteKey(const char *subkey, const char *key); + + //! Delete a value from a given key. + bool DeleteValue(const char *subkey, const char *key); + + //! Set value in a given key. + bool SetValue(const char *subkey, const char *key, + const char *value); + + //! Open the registry at toplevel/subkey. + bool Open(const char *toplevel, const char *subkey, + int readonly); + + //! Close the registry. + bool Close(); + + //! Read from local or global scope. On Windows this mean from local machine + // or local user. On unix this will read from $HOME/.Projectrc or + // /etc/Project + void GlobalScopeOn() { this->SetGlobalScope(1); } + void GlobalScopeOff() { this->SetGlobalScope(0); } + void SetGlobalScope(bool b); + bool GetGlobalScope(); + + // Set or get the toplevel registry key. + void SetTopLevel(const char* tl); + const char* GetTopLevel(); + + // Return true if registry opened + bool GetOpened() { return m_Opened; } + + // Should the registry be locked? + bool GetLocked() { return m_Locked; } + + enum { + READONLY, + READWRITE + }; + + // Return true if the character is space. + int IsSpace(char c); + +private: + RegistryHelper* Helper; + + bool m_Opened; + + bool m_Locked; +}; // End Class: Registry + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/RegularExpression.cxx b/RegularExpression.cxx new file mode 100644 index 000000000..f6eeebae4 --- /dev/null +++ b/RegularExpression.cxx @@ -0,0 +1,1251 @@ +/*============================================================================ + 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 +#include + +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(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; ®dummy = 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 (register const char*); +static char* regnext (register 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) { + register const char* scan; + register const char* longest; + register 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 = ®dummy; + regc(static_cast(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(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(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) { + register char* ret; + register char* br; + register char* ender; + register 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(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((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) { + register char* ret; + register char* chain; + register 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) { + register char* ret; + register char op; + register 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) { + register 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 '[':{ + register int rxpclass; + register 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(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:{ + register int len; + register 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) { + register char* ret; + register char* ptr; + + ret = regcode; + if (ret == ®dummy) { + 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 != ®dummy) + *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) { + register char* src; + register char* dst; + register char* place; + + if (regcode == ®dummy) { + 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) { + register char* scan; + register char* temp; + register int offset; + + if (p == ®dummy) + 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((offset >> 8) & 0377); + *(scan + 2) = static_cast(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 == ®dummy || 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 + +bool RegularExpression::find (kwsys_stl::string const& s) +{ + return find(s.c_str()); +} + + + +// 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) { + register 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) { + register int i; + register const char* *sp1; + register 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) { + register 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:{ + register size_t len; + register 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:{ + register int no; + register 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:{ + register int no; + register 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:{ + + register 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:{ + register char nextch; + register int no; + register const char* save; + register 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) { + register int count = 0; + register const char* scan; + register 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 (register const char* p) { + register int offset; + + if (p == ®dummy) + return (0); + + offset = NEXT(p); + if (offset == 0) + return (0); + + if (OP(p) == BACK) + return (p - offset); + else + return (p + offset); +} + +static char* regnext (register char* p) { + register int offset; + + if (p == ®dummy) + 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/RegularExpression.hxx.in b/RegularExpression.hxx.in new file mode 100644 index 000000000..62e9cad23 --- /dev/null +++ b/RegularExpression.hxx.in @@ -0,0 +1,414 @@ +/*============================================================================ + 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 <@KWSYS_NAMESPACE@/stl/string> + +/* Define this macro temporarily to keep the code readable. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsys_stl @KWSYS_NAMESPACE@_stl +#endif + +/* 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&); + + /** + * Destructor. + */ + inline ~RegularExpression(); + + /** + * Compile a regular expression into internal code + * for later pattern matching. + */ + bool compile (char 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. + */ + bool find (kwsys_stl::string const&); + + /** + * Index to start of first find. + */ + inline kwsys_stl::string::size_type start() const; + + /** + * Index to end of first find. + */ + inline kwsys_stl::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 + kwsys_stl::string::size_type start(int n) const; + kwsys_stl::string::size_type end(int n) const; + kwsys_stl::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 + kwsys_stl::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); + } +} + +/** + * Destroys and frees space allocated for the regular expression. + */ +inline RegularExpression::~RegularExpression () +{ +//#ifndef WIN32 + delete [] this->program; +//#endif +} + +/** + * Set the start position for the regular expression. + */ +inline kwsys_stl::string::size_type RegularExpression::start () const +{ + return static_cast( + this->startp[0] - searchstring); +} + + +/** + * Returns the start/end index of the last item found. + */ +inline kwsys_stl::string::size_type RegularExpression::end () const +{ + return static_cast( + 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 kwsys_stl::string::size_type RegularExpression::start(int n) const +{ + return static_cast( + this->startp[n] - searchstring); +} + + +/** + * Return end index of nth submatch. end(0) is the end of the full match. + */ +inline kwsys_stl::string::size_type RegularExpression::end(int n) const +{ + return static_cast( + this->endp[n] - searchstring); +} + +/** + * Return nth submatch as a string. + */ +inline kwsys_stl::string RegularExpression::match(int n) const +{ + if (this->startp[n]==0) + { + return kwsys_stl::string(""); + } + else + { + return kwsys_stl::string(this->startp[n], + static_cast( + this->endp[n] - this->startp[n])); + } +} + +} // namespace @KWSYS_NAMESPACE@ + +/* Undefine temporary macro. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsys_stl +#endif + +#endif diff --git a/SharedForward.h.in b/SharedForward.h.in new file mode 100644 index 000000000..8521099ad --- /dev/null +++ b/SharedForward.h.in @@ -0,0 +1,922 @@ +/*============================================================================ + 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. +*/ + +/*--------------------------------------------------------------------------*/ + +/* 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 /* size_t */ +#include +#include +#include +#include +#include + +#if defined(_WIN32) && !defined(__CYGWIN__) +# include +# include +# include +# define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */ +#else +# include +# include +#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 +# 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 = GetFullPathName(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 = CreateFile(file1, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + HANDLE h2 = CreateFile(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 = FormatMessage(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__) + 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 seperator 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[KWSYS_SHARED_FORWARD_MAXPATH*16] = 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; +} + +#else +# error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once." +#endif diff --git a/String.c b/String.c new file mode 100644 index 000000000..ed4a6c52a --- /dev/null +++ b/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 +#elif defined(__GNUC__) +# define KWSYS_STRING_USE_STRCASECMP +# include +#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/String.h.in b/String.h.in new file mode 100644 index 000000000..f5bab6e1a --- /dev/null +++ b/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 /* 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/String.hxx.in b/String.hxx.in new file mode 100644 index 000000000..4386c9eb7 --- /dev/null +++ b/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 <@KWSYS_NAMESPACE@/stl/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 @KWSYS_NAMESPACE@_stl::string +{ + /** The original string type. */ + typedef @KWSYS_NAMESPACE@_stl::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<@KWSYS_NAMESPACE@_stl::string const&>(l) < + static_cast<@KWSYS_NAMESPACE@_stl::string const&>(r)); + } +#endif + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/System.c b/System.c new file mode 100644 index 000000000..5d178bfa2 --- /dev/null +++ b/System.c @@ -0,0 +1,856 @@ +/*============================================================================ + 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 /* ptrdiff_t */ +#include /* malloc, free */ +#include /* strlen */ +#include /* isalpha */ + +#include + +#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 + +/* + +Notes: + +Make variable replacements open a can of worms. Sometimes they should +be quoted and sometimes not. Sometimes their replacement values are +already quoted. + +VS variables cause problems. In order to pass the referenced value +with spaces the reference must be quoted. If the variable value ends +in a backslash then it will escape the ending quote! In order to make +the ending backslash appear we need this: + + "$(InputDir)\" + +However if there is not a trailing backslash then this will put a +quote in the value so we need: + + "$(InputDir)" + +Make variable references are platform specific so we should probably +just NOT quote them and let the listfile author deal with it. + +*/ + +/* +TODO: For windows echo: + +To display a pipe (|) or redirection character (< or >) when using the +echo command, use a caret character immediately before the pipe or +redirection character (for example, ^>, ^<, or ^| ). If you need to +use the caret character itself (^), use two in a row (^^). +*/ + +/*--------------------------------------------------------------------------*/ +static int kwsysSystem_Shell__CharIsWhitespace(char c) +{ + return ((c == ' ') || (c == '\t')); +} + +/*--------------------------------------------------------------------------*/ +static int kwsysSystem_Shell__CharNeedsQuotesOnUnix(char c) +{ + return ((c == '\'') || (c == '`') || (c == ';') || (c == '#') || + (c == '&') || (c == '$') || (c == '(') || (c == ')') || + (c == '~') || (c == '<') || (c == '>') || (c == '|') || + (c == '*') || (c == '^') || (c == '\\')); +} + +/*--------------------------------------------------------------------------*/ +static int kwsysSystem_Shell__CharNeedsQuotesOnWindows(char c) +{ + return ((c == '\'') || (c == '#') || (c == '&') || + (c == '<') || (c == '>') || (c == '|') || (c == '^')); +} + +/*--------------------------------------------------------------------------*/ +static int kwsysSystem_Shell__CharNeedsQuotes(char c, int isUnix, int flags) +{ + /* On Windows the built-in command shell echo never needs quotes. */ + if(!isUnix && (flags & kwsysSystem_Shell_Flag_EchoWindows)) + { + return 0; + } + + /* On all platforms quotes are needed to preserve whitespace. */ + if(kwsysSystem_Shell__CharIsWhitespace(c)) + { + return 1; + } + + if(isUnix) + { + /* On UNIX several special characters need quotes to preserve them. */ + if(kwsysSystem_Shell__CharNeedsQuotesOnUnix(c)) + { + return 1; + } + } + else + { + /* On Windows several special characters need quotes to preserve them. */ + if(kwsysSystem_Shell__CharNeedsQuotesOnWindows(c)) + { + return 1; + } + } + return 0; +} + +/*--------------------------------------------------------------------------*/ +static int kwsysSystem_Shell__CharIsMakeVariableName(char c) +{ + return c && (c == '_' || isalpha(((int)c))); +} + +/*--------------------------------------------------------------------------*/ +static const char* kwsysSystem_Shell__SkipMakeVariables(const char* c) +{ + while(*c == '$' && *(c+1) == '(') + { + const char* skip = c+2; + while(kwsysSystem_Shell__CharIsMakeVariableName(*skip)) + { + ++skip; + } + if(*skip == ')') + { + c = skip+1; + } + else + { + break; + } + } + return c; +} + +/* +Allowing make variable replacements opens a can of worms. Sometimes +they should be quoted and sometimes not. Sometimes their replacement +values are already quoted or contain escapes. + +Some Visual Studio variables cause problems. In order to pass the +referenced value with spaces the reference must be quoted. If the +variable value ends in a backslash then it will escape the ending +quote! In order to make the ending backslash appear we need this: + + "$(InputDir)\" + +However if there is not a trailing backslash then this will put a +quote in the value so we need: + + "$(InputDir)" + +This macro decides whether we quote an argument just because it +contains a make variable reference. This should be replaced with a +flag later when we understand applications of this better. +*/ +#define KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES 0 + +/*--------------------------------------------------------------------------*/ +static int kwsysSystem_Shell__ArgumentNeedsQuotes(const char* in, int isUnix, + int flags) +{ + /* The empty string needs quotes. */ + if(!*in) + { + return 1; + } + + /* Scan the string for characters that require quoting. */ + { + const char* c; + for(c=in; *c; ++c) + { + /* Look for $(MAKEVAR) syntax if requested. */ + if(flags & kwsysSystem_Shell_Flag_AllowMakeVariables) + { +#if KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES + const char* skip = kwsysSystem_Shell__SkipMakeVariables(c); + if(skip != c) + { + /* We need to quote make variable references to preserve the + string with contents substituted in its place. */ + return 1; + } +#else + /* Skip over the make variable references if any are present. */ + c = kwsysSystem_Shell__SkipMakeVariables(c); + + /* Stop if we have reached the end of the string. */ + if(!*c) + { + break; + } +#endif + } + + /* Check whether this character needs quotes. */ + if(kwsysSystem_Shell__CharNeedsQuotes(*c, isUnix, flags)) + { + return 1; + } + } + } + + /* On Windows some single character arguments need quotes. */ + if(!isUnix && *in && !*(in+1)) + { + char c = *in; + if((c == '?') || (c == '&') || (c == '^') || (c == '|') || (c == '#')) + { + return 1; + } + } + + return 0; +} + +/*--------------------------------------------------------------------------*/ +static int kwsysSystem_Shell__GetArgumentSize(const char* in, + int isUnix, int flags) +{ + /* Start with the length of the original argument, plus one for + either a terminating null or a separating space. */ + int size = (int)strlen(in) + 1; + + /* String iterator. */ + const char* c; + + /* Keep track of how many backslashes have been encountered in a row. */ + int windows_backslashes = 0; + + /* Scan the string for characters that require escaping or quoting. */ + for(c=in; *c; ++c) + { + /* Look for $(MAKEVAR) syntax if requested. */ + if(flags & kwsysSystem_Shell_Flag_AllowMakeVariables) + { + /* Skip over the make variable references if any are present. */ + c = kwsysSystem_Shell__SkipMakeVariables(c); + + /* Stop if we have reached the end of the string. */ + if(!*c) + { + break; + } + } + + /* Check whether this character needs escaping for the shell. */ + if(isUnix) + { + /* On Unix a few special characters need escaping even inside a + quoted argument. */ + if(*c == '\\' || *c == '"' || *c == '`' || *c == '$') + { + /* This character needs a backslash to escape it. */ + ++size; + } + } + else if(flags & kwsysSystem_Shell_Flag_EchoWindows) + { + /* On Windows the built-in command shell echo never needs escaping. */ + } + else + { + /* 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. */ + 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 this character needs escaping for a make tool. */ + if(*c == '$') + { + if(flags & kwsysSystem_Shell_Flag_Make) + { + /* In Makefiles a dollar is written $$ so we need one extra + character. */ + ++size; + } + else if(flags & kwsysSystem_Shell_Flag_VSIDE) + { + /* In a VS IDE a dollar is written "$" so we need two extra + characters. */ + size += 2; + } + } + else if(*c == '#') + { + if((flags & kwsysSystem_Shell_Flag_Make) && + (flags & kwsysSystem_Shell_Flag_WatcomWMake)) + { + /* In Watcom WMake makefiles a pound is written $# so we need + one extra character. */ + ++size; + } + } + else if(*c == '%') + { + if((flags & kwsysSystem_Shell_Flag_VSIDE) || + ((flags & kwsysSystem_Shell_Flag_Make) && + ((flags & kwsysSystem_Shell_Flag_MinGWMake) || + (flags & kwsysSystem_Shell_Flag_NMake)))) + { + /* In the VS IDE, NMake, or MinGW make a percent is written %% + so we need one extra characters. */ + size += 1; + } + } + else if(*c == ';') + { + if(flags & kwsysSystem_Shell_Flag_VSIDE) + { + /* In a VS IDE a semicolon is written ";" so we need two extra + characters. */ + size += 2; + } + } + } + + /* Check whether the argument needs surrounding quotes. */ + if(kwsysSystem_Shell__ArgumentNeedsQuotes(in, isUnix, flags)) + { + /* Surrounding quotes are needed. Allocate space for them. */ + size += 2; + + /* We must escape all ending backslashes when quoting on windows. */ + size += windows_backslashes; + } + + return size; +} + +/*--------------------------------------------------------------------------*/ +static char* kwsysSystem_Shell__GetArgument(const char* in, char* out, + int isUnix, int flags) +{ + /* 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. */ + int needQuotes = kwsysSystem_Shell__ArgumentNeedsQuotes(in, isUnix, flags); + if(needQuotes) + { + /* Add the opening quote for this argument. */ + *out++ = '"'; + } + + /* Scan the string for characters that require escaping or quoting. */ + for(c=in; *c; ++c) + { + /* Look for $(MAKEVAR) syntax if requested. */ + if(flags & kwsysSystem_Shell_Flag_AllowMakeVariables) + { + const char* skip = kwsysSystem_Shell__SkipMakeVariables(c); + if(skip != c) + { + /* Copy to the end of the make variable references. */ + while(c != skip) + { + *out++ = *c++; + } + + /* The make variable reference eliminates any escaping needed + for preceding backslashes. */ + windows_backslashes = 0; + + /* Stop if we have reached the end of the string. */ + if(!*c) + { + break; + } + } + } + + /* Check whether this character needs escaping for the shell. */ + if(isUnix) + { + /* On Unix a few special characters need escaping even inside a + quoted argument. */ + if(*c == '\\' || *c == '"' || *c == '`' || *c == '$') + { + /* This character needs a backslash to escape it. */ + *out++ = '\\'; + } + } + else if(flags & kwsysSystem_Shell_Flag_EchoWindows) + { + /* On Windows the built-in command shell echo never needs escaping. */ + } + else + { + /* 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; + } + } + + /* Check whether this character needs escaping for a make tool. */ + if(*c == '$') + { + if(flags & kwsysSystem_Shell_Flag_Make) + { + /* In Makefiles a dollar is written $$. The make tool will + replace it with just $ before passing it to the shell. */ + *out++ = '$'; + *out++ = '$'; + } + else if(flags & kwsysSystem_Shell_Flag_VSIDE) + { + /* In a VS IDE a dollar is written "$". If this is written in + an un-quoted argument it starts a quoted segment, inserts + the $ and ends the segment. If it is written in a quoted + argument it ends quoting, inserts the $ and restarts + quoting. Either way the $ is isolated from surrounding + text to avoid looking like a variable reference. */ + *out++ = '"'; + *out++ = '$'; + *out++ = '"'; + } + else + { + /* Otherwise a dollar is written just $. */ + *out++ = '$'; + } + } + else if(*c == '#') + { + if((flags & kwsysSystem_Shell_Flag_Make) && + (flags & kwsysSystem_Shell_Flag_WatcomWMake)) + { + /* In Watcom WMake makefiles a pound is written $#. The make + tool will replace it with just # before passing it to the + shell. */ + *out++ = '$'; + *out++ = '#'; + } + else + { + /* Otherwise a pound is written just #. */ + *out++ = '#'; + } + } + else if(*c == '%') + { + if((flags & kwsysSystem_Shell_Flag_VSIDE) || + ((flags & kwsysSystem_Shell_Flag_Make) && + ((flags & kwsysSystem_Shell_Flag_MinGWMake) || + (flags & kwsysSystem_Shell_Flag_NMake)))) + { + /* In the VS IDE, NMake, or MinGW make a percent is written %%. */ + *out++ = '%'; + *out++ = '%'; + } + else + { + /* Otherwise a percent is written just %. */ + *out++ = '%'; + } + } + else if(*c == ';') + { + if(flags & kwsysSystem_Shell_Flag_VSIDE) + { + /* In a VS IDE a semicolon is written ";". If this is written + in an un-quoted argument it starts a quoted segment, + inserts the ; and ends the segment. If it is written in a + quoted argument it ends quoting, inserts the ; and restarts + quoting. Either way the ; is isolated. */ + *out++ = '"'; + *out++ = ';'; + *out++ = '"'; + } + else + { + /* Otherwise a semicolon is written just ;. */ + *out++ = ';'; + } + } + else + { + /* Store this character. */ + *out++ = *c; + } + } + + if(needQuotes) + { + /* 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; +} + +/*--------------------------------------------------------------------------*/ +char* kwsysSystem_Shell_GetArgumentForWindows(const char* in, + char* out, + int flags) +{ + return kwsysSystem_Shell__GetArgument(in, out, 0, flags); +} + +/*--------------------------------------------------------------------------*/ +char* kwsysSystem_Shell_GetArgumentForUnix(const char* in, + char* out, + int flags) +{ + return kwsysSystem_Shell__GetArgument(in, out, 1, flags); +} + +/*--------------------------------------------------------------------------*/ +int kwsysSystem_Shell_GetArgumentSizeForWindows(const char* in, int flags) +{ + return kwsysSystem_Shell__GetArgumentSize(in, 0, flags); +} + +/*--------------------------------------------------------------------------*/ +int kwsysSystem_Shell_GetArgumentSizeForUnix(const char* in, int flags) +{ + return kwsysSystem_Shell__GetArgumentSize(in, 1, flags); +} + +/*--------------------------------------------------------------------------*/ +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/System.h.in b/System.h.in new file mode 100644 index 000000000..549db900c --- /dev/null +++ b/System.h.in @@ -0,0 +1,162 @@ +/*============================================================================ + 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) +# define kwsysSystem_Shell_GetArgumentForWindows kwsys_ns(System_Shell_GetArgumentForWindows) +# define kwsysSystem_Shell_GetArgumentForUnix kwsys_ns(System_Shell_GetArgumentForUnix) +# define kwsysSystem_Shell_GetArgumentSizeForWindows kwsys_ns(System_Shell_GetArgumentSizeForWindows) +# define kwsysSystem_Shell_GetArgumentSizeForUnix kwsys_ns(System_Shell_GetArgumentSizeForUnix) +# define kwsysSystem_Shell_Flag_e kwsys_ns(System_Shell_Flag_e) +# define kwsysSystem_Shell_Flag_Make kwsys_ns(System_Shell_Flag_Make) +# define kwsysSystem_Shell_Flag_VSIDE kwsys_ns(System_Shell_Flag_VSIDE) +# define kwsysSystem_Shell_Flag_EchoWindows kwsys_ns(System_Shell_Flag_EchoWindows) +# define kwsysSystem_Shell_Flag_WatcomWMake kwsys_ns(System_Shell_Flag_WatcomWMake) +# define kwsysSystem_Shell_Flag_MinGWMake kwsys_ns(System_Shell_Flag_MinGWMake) +# define kwsysSystem_Shell_Flag_NMake kwsys_ns(System_Shell_Flag_NMake) +# define kwsysSystem_Shell_Flag_AllowMakeVariables kwsys_ns(System_Shell_Flag_AllowMakeVariables) +#endif + +#ifdef __VMS +#define @KWSYS_NAMESPACE@System_Shell_GetArgumentForUnix \ + @KWSYS_NAMESPACE@System_Shell_UnixGA +#define @KWSYS_NAMESPACE@System_Shell_GetArgumentSizeForUnix \ + @KWSYS_NAMESPACE@System_Shell_UnixGAS +#define @KWSYS_NAMESPACE@System_Shell_GetArgumentForWindows \ + @KWSYS_NAMESPACE@System_Shell_WindowsGA +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/** + * Transform the given command line argument for use in a Windows or + * Unix shell. Returns a pointer to the end of the command line + * argument in the provided output buffer. Flags may be passed to + * modify the generated quoting and escape sequences to work under + * alternative environments. + */ +kwsysEXPORT char* kwsysSystem_Shell_GetArgumentForWindows(const char* in, + char* out, + int flags); +kwsysEXPORT char* kwsysSystem_Shell_GetArgumentForUnix(const char* in, + char* out, + int flags); + +/** + * Compute the size of the buffer required to store the output from + * kwsysSystem_Shell_GetArgumentForWindows or + * kwsysSystem_Shell_GetArgumentForUnix. The flags passed must be + * identical between the two calls. + */ +kwsysEXPORT int kwsysSystem_Shell_GetArgumentSizeForWindows(const char* in, + int flags); +kwsysEXPORT int kwsysSystem_Shell_GetArgumentSizeForUnix(const char* in, + int flags); + +/** + * Flags to pass to kwsysSystem_Shell_GetArgumentForWindows or + * kwsysSystem_Shell_GetArgumentForUnix. These modify the generated + * quoting and escape sequences to work under alternative + * environments. + */ +enum kwsysSystem_Shell_Flag_e +{ + /** The target shell is in a makefile. */ + kwsysSystem_Shell_Flag_Make = (1<<0), + + /** The target shell is in a VS project file. Do not use with + Shell_Flag_Make. */ + kwsysSystem_Shell_Flag_VSIDE = (1<<1), + + /** In a windows shell the argument is being passed to "echo". */ + kwsysSystem_Shell_Flag_EchoWindows = (1<<2), + + /** The target shell is in a Watcom WMake makefile. */ + kwsysSystem_Shell_Flag_WatcomWMake = (1<<3), + + /** The target shell is in a MinGW Make makefile. */ + kwsysSystem_Shell_Flag_MinGWMake = (1<<4), + + /** The target shell is in a NMake makefile. */ + kwsysSystem_Shell_Flag_NMake = (1<<6), + + /** Make variable reference syntax $(MAKEVAR) should not be escaped + to allow a build tool to replace it. Replacement values + containing spaces, quotes, backslashes, or other + non-alphanumeric characters that have significance to some makes + or shells produce undefined behavior. */ + kwsysSystem_Shell_Flag_AllowMakeVariables = (1<<5) +}; + +/** + * 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 +# undef kwsysSystem_Shell_GetArgumentForWindows +# undef kwsysSystem_Shell_GetArgumentForUnix +# undef kwsysSystem_Shell_GetArgumentSizeForWindows +# undef kwsysSystem_Shell_GetArgumentSizeForUnix +# undef kwsysSystem_Shell_Flag_e +# undef kwsysSystem_Shell_Flag_Make +# undef kwsysSystem_Shell_Flag_VSIDE +# undef kwsysSystem_Shell_Flag_EchoWindows +# undef kwsysSystem_Shell_Flag_WatcomWMake +# undef kwsysSystem_Shell_Flag_MinGWMake +# undef kwsysSystem_Shell_Flag_NMake +# undef kwsysSystem_Shell_Flag_AllowMakeVariables +# endif +#endif + +#endif diff --git a/SystemInformation.cxx b/SystemInformation.cxx new file mode 100644 index 000000000..e1ee873b4 --- /dev/null +++ b/SystemInformation.cxx @@ -0,0 +1,3675 @@ +/*============================================================================ + 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 +# include // WSADATA, include before sys/types.h +#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(stl/string) +#include KWSYS_HEADER(stl/vector) +#include KWSYS_HEADER(ios/iosfwd) +#include KWSYS_HEADER(SystemInformation.hxx) +#include KWSYS_HEADER(Process.h) +#include KWSYS_HEADER(ios/iostream) +#include KWSYS_HEADER(ios/sstream) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "SystemInformation.hxx.in" +# include "Process.h.in" +# include "Configure.hxx.in" +# include "kwsys_stl.hxx.in" +# include "kwsys_stl_vector.in" +# include "kwsys_stl_iosfwd.in" +# include "kwsys_ios_sstream.h.in" +# include "kwsys_ios_iostream.h.in" +#endif + +#ifndef WIN32 +# include // int uname(struct utsname *buf); +#endif + +#ifdef _WIN32 +# include +#endif + +#ifdef __APPLE__ +#include +#include +#include +#include +#include +#endif + +#ifdef __linux +# include +# include +# include +# include // int isdigit(int c); +# include // extern int errno; +# include +#elif defined( __hpux ) +# include +# include +#endif + +#ifdef __HAIKU__ +#include +#endif + +#include +#include +#include +#include + + +namespace KWSYS_NAMESPACE +{ + +// Create longlong +#if KWSYS_USE_LONG_LONG + typedef long long LongLong; +#elif KWSYS_USE___INT64 + typedef __int64 LongLong; +#else +# error "No Long Long" +#endif + + +// Define SystemInformationImplementation class +typedef void (*DELAY_FUNC)(unsigned int uiMS); + + +class SystemInformationImplementation +{ +public: + SystemInformationImplementation (); + ~SystemInformationImplementation (); + + const char * GetVendorString(); + const char * GetVendorID(); + kwsys_stl::string GetTypeID(); + kwsys_stl::string GetFamilyID(); + kwsys_stl::string GetModelID(); + kwsys_stl::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(); + 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(); + + /** 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; + kwsys_stl::string ProcessorName; + kwsys_stl::string Vendor; + kwsys_stl::string SerialNumber; + } 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, UnknownManufacturer + }; + +protected: + // Functions. + 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(); + + Manufacturer ChipManufacturer; + CPUFeatures Features; + ID ChipID; + float CPUSpeedInMHz; + unsigned int NumberOfLogicalCPU; + unsigned int NumberOfPhysicalCPU; + + int CPUCount(); + unsigned char LogicalCPUPerPhysicalCPU(); + unsigned char GetAPICId(); + unsigned int IsHyperThreadingSupported(); + LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); + + // For Linux and Cygwin, /proc/cpuinfo formats are slightly different + int RetreiveInformationFromCpuInfoFile(); + kwsys_stl::string ExtractValueFromCpuInfoFile(kwsys_stl::string buffer, + const char* word, size_t init=0); + + static void Delay (unsigned int); + static void DelayOverhead (unsigned int); + + void FindManufacturer(); + + // For Mac + bool ParseSysCtl(); + void CallSwVers(); + void TrimNewline(kwsys_stl::string&); + kwsys_stl::string ExtractValueFromSysCtl(const char* word); + kwsys_stl::string SysCtlBuffer; + + // For Solaris + bool QuerySolarisInfo(); + kwsys_stl::string ParseValueFromKStat(const char* arguments); + kwsys_stl::string RunProcess(kwsys_stl::vector args); + + //For Haiku OS + bool QueryHaikuInfo(); + + //For QNX + bool QueryQNXMemory(); + bool QueryQNXProcessor(); + + // Evaluate the memory information. + int QueryMemory(); + size_t TotalVirtualMemory; + size_t AvailableVirtualMemory; + size_t TotalPhysicalMemory; + size_t AvailablePhysicalMemory; + + size_t CurrentPositionInFile; + + // Operating System information + bool QueryOSInformation(); + kwsys_stl::string OSName; + kwsys_stl::string Hostname; + kwsys_stl::string OSRelease; + kwsys_stl::string OSVersion; + kwsys_stl::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(); +} + +kwsys_stl::string SystemInformation::GetTypeID() +{ + return this->Implementation->GetTypeID(); +} + +kwsys_stl::string SystemInformation::GetFamilyID() +{ + return this->Implementation->GetFamilyID(); +} + +kwsys_stl::string SystemInformation::GetModelID() +{ + return this->Implementation->GetModelID(); +} + +kwsys_stl::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); +} + +const char * SystemInformation::GetOSName() +{ + return this->Implementation->GetOSName(); +} + +const char * SystemInformation::GetHostname() +{ + return this->Implementation->GetHostname(); +} + +const char * SystemInformation::GetOSRelease() +{ + return this->Implementation->GetOSRelease(); +} + +const char * SystemInformation::GetOSVersion() +{ + return this->Implementation->GetOSVersion(); +} + +const char * SystemInformation::GetOSPlatform() +{ + return this->Implementation->GetOSPlatform(); +} + +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(); +} + +/** 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 + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) +#define USE_ASM_INSTRUCTIONS 1 +#else +#define USE_ASM_INSTRUCTIONS 0 +#endif + +#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 CPUID_AWARE_COMPILER +#ifdef CPUID_AWARE_COMPILER + #define CPUID_INSTRUCTION cpuid +#else + #define CPUID_INSTRUCTION _asm _emit 0x0f _asm _emit 0xa2 +#endif + +#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 + + +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(); + 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->QuerySolarisInfo(); +#elif defined(__HAIKU__) + this->QueryHaikuInfo(); +#elif defined(__QNX__) + this->QueryQNXProcessor(); +#else + this->RetreiveInformationFromCpuInfoFile(); +#endif +} + +void SystemInformationImplementation::RunOSCheck() +{ + this->QueryOSInformation(); +} + +void SystemInformationImplementation::RunMemoryCheck() +{ +#if defined(__APPLE__) + this->ParseSysCtl(); +#elif defined (__SVR4) && defined (__sun) + this->QuerySolarisInfo(); +#elif defined(__HAIKU__) + this->QueryHaikuInfo(); +#elif defined(__QNX__) + this->QueryQNXMemory(); +#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() +{ + return this->Hostname.c_str(); +} + +/** 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"; + default: + return "Unknown Manufacturer"; + } +} + +/** Return the type ID of the CPU */ +kwsys_stl::string SystemInformationImplementation::GetTypeID() +{ + kwsys_ios::ostringstream str; + str << this->ChipID.Type; + return str.str(); +} + +/** Return the family of the CPU present */ +kwsys_stl::string SystemInformationImplementation::GetFamilyID() +{ + kwsys_ios::ostringstream str; + str << this->ChipID.Family; + return str.str(); +} + +// Return the model of CPU present */ +kwsys_stl::string SystemInformationImplementation::GetModelID() +{ + kwsys_ios::ostringstream str; + str << this->ChipID.Model; + return str.str(); +} + +/** Return the stepping code of the CPU present. */ +kwsys_stl::string SystemInformationImplementation::GetSteppingCode() +{ + kwsys_ios::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_ASM_INSTRUCTIONS + // Use SEH to determine CPUID presence + __try { + _asm { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + mov eax, 0 + CPUID_INSTRUCTION + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + // Stop the class from trying to use CPUID again! + return false; + } + + // The cpuid instruction succeeded. + return true; + +#else + // Assume no cpuid instruction. + return false; +#endif +} + + +bool SystemInformationImplementation::RetrieveCPUFeatures() +{ +#if USE_ASM_INSTRUCTIONS + int localCPUFeatures = 0; + int localCPUAdvanced = 0; + + // Use assembly to detect CPUID information... + __try { + _asm { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; 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 processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID + ; edx: CPU feature flags + mov eax,1 + CPUID_INSTRUCTION + mov localCPUFeatures, edx + mov localCPUAdvanced, ebx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + return false; + } + + // Retrieve the features of CPU present. + this->Features.HasFPU = ((localCPUFeatures & 0x00000001) != 0); // FPU Present --> Bit 0 + this->Features.HasTSC = ((localCPUFeatures & 0x00000010) != 0); // TSC Present --> Bit 4 + this->Features.HasAPIC = ((localCPUFeatures & 0x00000200) != 0); // APIC Present --> Bit 9 + this->Features.HasMTRR = ((localCPUFeatures & 0x00001000) != 0); // MTRR Present --> Bit 12 + this->Features.HasCMOV = ((localCPUFeatures & 0x00008000) != 0); // CMOV Present --> Bit 15 + this->Features.HasSerial = ((localCPUFeatures & 0x00040000) != 0); // Serial Present --> Bit 18 + this->Features.HasACPI = ((localCPUFeatures & 0x00400000) != 0); // ACPI Capable --> Bit 22 + this->Features.HasMMX = ((localCPUFeatures & 0x00800000) != 0); // MMX Present --> Bit 23 + this->Features.HasSSE = ((localCPUFeatures & 0x02000000) != 0); // SSE Present --> Bit 25 + this->Features.HasSSE2 = ((localCPUFeatures & 0x04000000) != 0); // SSE2 Present --> Bit 26 + this->Features.HasThermal = ((localCPUFeatures & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29 + this->Features.HasIA64 = ((localCPUFeatures & 0x40000000) != 0); // IA64 Present --> Bit 30 + + // 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; + } + + // Retrieve Intel specific extended features. + if (this->ChipManufacturer == Intel) + { + this->Features.ExtendedFeatures.SupportsHyperthreading = ((localCPUFeatures & 0x10000000) != 0); // Intel specific: Hyperthreading --> Bit 28 + this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (this->Features.ExtendedFeatures.SupportsHyperthreading) ? ((localCPUAdvanced & 0x00FF0000) >> 16) : 1; + + if ((this->Features.ExtendedFeatures.SupportsHyperthreading) && (this->Features.HasAPIC)) + { + // Retrieve APIC information if there is one present. + this->Features.ExtendedFeatures.APIC_ID = ((localCPUAdvanced & 0xFF000000) >> 24); + } + } + + return true; + +#else + return false; +#endif +} + + +/** Find the manufacturer given the vendor id */ +void SystemInformationImplementation::FindManufacturer() +{ + 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 == "Motorola") this->ChipManufacturer = Motorola; // Motorola Microelectronics + else this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer +} + + +/** */ +bool SystemInformationImplementation::RetrieveCPUIdentity() +{ +#if USE_ASM_INSTRUCTIONS + int localCPUVendor[3]; + int localCPUSignature; + + // Use assembly to detect CPUID information... + __try + { + _asm + { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; 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. + mov eax, 0 + CPUID_INSTRUCTION + mov localCPUVendor[0 * TYPE int], ebx + mov localCPUVendor[1 * TYPE int], edx + mov localCPUVendor[2 * TYPE int], ecx + + ; <> + ; 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 processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID + ; edx: CPU feature flags + mov eax,1 + CPUID_INSTRUCTION + mov localCPUSignature, eax + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + return false; + } + + // Process the returned information. + char vbuf[13]; + memcpy (&(vbuf[0]), &(localCPUVendor[0]), sizeof (int)); + memcpy (&(vbuf[4]), &(localCPUVendor[1]), sizeof (int)); + memcpy (&(vbuf[8]), &(localCPUVendor[2]), sizeof (int)); + vbuf[12] = '\0'; + this->ChipID.Vendor = vbuf; + + this->FindManufacturer(); + + // Retrieve the family of CPU present. + this->ChipID.ExtendedFamily = ((localCPUSignature & 0x0FF00000) >> 20); // Bits 27..20 Used + this->ChipID.ExtendedModel = ((localCPUSignature & 0x000F0000) >> 16); // Bits 19..16 Used + this->ChipID.Type = ((localCPUSignature & 0x0000F000) >> 12); // Bits 15..12 Used + this->ChipID.Family = ((localCPUSignature & 0x00000F00) >> 8); // Bits 11..8 Used + this->ChipID.Model = ((localCPUSignature & 0x000000F0) >> 4); // Bits 7..4 Used + this->ChipID.Revision = ((localCPUSignature & 0x0000000F) >> 0); // Bits 3..0 Used + + return true; + +#else + return false; +#endif +} + + +/** */ +bool SystemInformationImplementation::RetrieveCPUCacheDetails() +{ +#if USE_ASM_INSTRUCTIONS + 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)) + { + // Use assembly to retrieve the L1 cache information ... + __try + { + _asm + { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; eax = 0x80000005 --> eax: L1 cache information - Part 1 of 4. + ; ebx: L1 cache information - Part 2 of 4. + ; edx: L1 cache information - Part 3 of 4. + ; ecx: L1 cache information - Part 4 of 4. + mov eax, 0x80000005 + CPUID_INSTRUCTION + mov L1Cache[0 * TYPE int], eax + mov L1Cache[1 * TYPE int], ebx + mov L1Cache[2 * TYPE int], ecx + mov L1Cache[3 * TYPE int], edx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + 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)) + { + // Use assembly to retrieve the L2 cache information ... + __try + { + _asm + { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; eax = 0x80000006 --> eax: L2 cache information - Part 1 of 4. + ; ebx: L2 cache information - Part 2 of 4. + ; edx: L2 cache information - Part 3 of 4. + ; ecx: L2 cache information - Part 4 of 4. + mov eax, 0x80000006 + CPUID_INSTRUCTION + mov L2Cache[0 * TYPE int], eax + mov L2Cache[1 * TYPE int], ebx + mov L2Cache[2 * TYPE int], ecx + mov L2Cache[3 * TYPE int], edx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + 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_ASM_INSTRUCTIONS + 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 { + // Use assembly to retrieve the L2 cache information ... + __try { + _asm { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; eax = 2 --> eax: TLB and cache information - Part 1 of 4. + ; ebx: TLB and cache information - Part 2 of 4. + ; ecx: TLB and cache information - Part 3 of 4. + ; edx: TLB and cache information - Part 4 of 4. + mov eax, 2 + CPUID_INSTRUCTION + mov TLBCacheData[0 * TYPE int], eax + mov TLBCacheData[1 * TYPE int], ebx + mov TLBCacheData[2 * TYPE int], ecx + mov TLBCacheData[3 * TYPE int], edx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + 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 occured. + 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 occured. + 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) + // First of all we check to see if the RDTSC (0x0F, 0x31) instruction is + // supported. If not, we fallback to trying to read this value from the + // registry: + // + if (!this->Features.HasTSC) + { + HKEY hKey = NULL; + LONG err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, + KEY_READ, &hKey); + + if (ERROR_SUCCESS == err) + { + DWORD dwType = 0; + DWORD data = 0; + DWORD dwSize = sizeof(DWORD); + + err = RegQueryValueEx(hKey, "~MHz", 0, + &dwType, (LPBYTE) &data, &dwSize); + + if (ERROR_SUCCESS == err) + { + this->CPUSpeedInMHz = (float) data; + retrieved = true; + } + + RegCloseKey(hKey); + hKey = NULL; + } + + return retrieved; + } + + unsigned int uiRepetitions = 1; + unsigned int uiMSecPerRepetition = 50; + __int64 i64Total = 0; + __int64 i64Overhead = 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; +#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 MaxCPUExtendedLevel = 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_ASM_INSTRUCTIONS + + // Use assembly to detect CPUID information... + __try { + _asm { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; eax = 0x80000000 --> eax: maximum supported extended level + mov eax,0x80000000 + CPUID_INSTRUCTION + mov MaxCPUExtendedLevel, eax + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + return false; + } +#endif + + // Now we have to check the level wanted vs level returned... + int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF); + int nLevelReturn = (MaxCPUExtendedLevel & 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(0x80000001))) + { + return false; + } + +#if USE_ASM_INSTRUCTIONS + int localCPUExtendedFeatures = 0; + + // Use assembly to detect CPUID information... + __try + { + _asm + { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; eax = 0x80000001 --> 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 processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID + ; edx: CPU feature flags + mov eax,0x80000001 + CPUID_INSTRUCTION + mov localCPUExtendedFeatures, edx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + return false; + } + + // Retrieve the extended features of CPU present. + this->Features.ExtendedFeatures.Has3DNow = ((localCPUExtendedFeatures & 0x80000000) != 0); // 3DNow Present --> Bit 31. + this->Features.ExtendedFeatures.Has3DNowPlus = ((localCPUExtendedFeatures & 0x40000000) != 0); // 3DNow+ Present -- > Bit 30. + this->Features.ExtendedFeatures.HasSSEMMX = ((localCPUExtendedFeatures & 0x00400000) != 0); // SSE MMX Present --> Bit 22. + this->Features.ExtendedFeatures.SupportsMP = ((localCPUExtendedFeatures & 0x00080000) != 0); // MP Capable -- > Bit 19. + + // Retrieve AMD specific extended features. + if (this->ChipManufacturer == AMD) + { + this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 0x00400000) != 0); // AMD specific: MMX-SSE --> Bit 22 + } + + // Retrieve Cyrix specific extended features. + if (this->ChipManufacturer == Cyrix) + { + this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 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_ASM_INSTRUCTIONS + int SerialNumber[3]; + + // Use assembly to detect CPUID information... + __try { + _asm { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; 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 + mov eax, 3 + CPUID_INSTRUCTION + mov SerialNumber[0 * TYPE int], ebx + mov SerialNumber[1 * TYPE int], ecx + mov SerialNumber[2 * TYPE int], edx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + return false; + } + + // Process the returned information. + char sn[128]; + sprintf (sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x", + ((SerialNumber[0] & 0xff000000) >> 24), + ((SerialNumber[0] & 0x00ff0000) >> 16), + ((SerialNumber[0] & 0x0000ff00) >> 8), + ((SerialNumber[0] & 0x000000ff) >> 0), + ((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)); + 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(0x80000007))) + { + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false; + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false; + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false; + return false; + } + +#if USE_ASM_INSTRUCTIONS + int localCPUPowerManagement = 0; + + + // Use assembly to detect CPUID information... + __try { + _asm { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; eax = 0x80000007 --> edx: get processor power management + mov eax,0x80000007 + CPUID_INSTRUCTION + mov localCPUPowerManagement, edx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + return false; + } + + // Check for the power management capabilities of the CPU. + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = ((localCPUPowerManagement & 0x00000001) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = ((localCPUPowerManagement & 0x00000002) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = ((localCPUPowerManagement & 0x00000004) != 0); + + return true; + +#else + return false; +#endif +} + +void SystemInformationStripLeadingSpace(kwsys_stl::string& str) +{ + // Because some manufacturers have leading white space - we have to post-process the name. + kwsys_stl::string::size_type pos = str.find_first_not_of(" "); + if(pos != kwsys_stl::string::npos) + { + str = str.substr(pos); + } +} + +/** */ +bool SystemInformationImplementation::RetrieveExtendedCPUIdentity() +{ + // Check to see if what we are about to do is supported... + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000002))) + return false; + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000003))) + return false; + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000004))) + return false; + +#if USE_ASM_INSTRUCTIONS + int CPUExtendedIdentity[12]; + + // Use assembly to detect CPUID information... + __try { + _asm { +#ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser doesn't know about <>, and so doesn't expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +#endif + ; <> + ; eax = 0x80000002 --> eax, ebx, ecx, edx: get processor name string (part 1) + mov eax,0x80000002 + CPUID_INSTRUCTION + mov CPUExtendedIdentity[0 * TYPE int], eax + mov CPUExtendedIdentity[1 * TYPE int], ebx + mov CPUExtendedIdentity[2 * TYPE int], ecx + mov CPUExtendedIdentity[3 * TYPE int], edx + + ; <> + ; eax = 0x80000003 --> eax, ebx, ecx, edx: get processor name string (part 2) + mov eax,0x80000003 + CPUID_INSTRUCTION + mov CPUExtendedIdentity[4 * TYPE int], eax + mov CPUExtendedIdentity[5 * TYPE int], ebx + mov CPUExtendedIdentity[6 * TYPE int], ecx + mov CPUExtendedIdentity[7 * TYPE int], edx + + ; <> + ; eax = 0x80000004 --> eax, ebx, ecx, edx: get processor name string (part 3) + mov eax,0x80000004 + CPUID_INSTRUCTION + mov CPUExtendedIdentity[8 * TYPE int], eax + mov CPUExtendedIdentity[9 * TYPE int], ebx + mov CPUExtendedIdentity[10 * TYPE int], ecx + mov CPUExtendedIdentity[11 * TYPE int], edx + +#ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +#endif + } + } + __except(1) + { + 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; + + // 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; + default: + this->ChipID.ProcessorName = "Unknown family"; // We cannot identify the processor. + return false; + } + + return true; +} + + +/** Extract a value from the CPUInfo file */ +kwsys_stl::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(kwsys_stl::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) + { + return buffer.substr(pos+2,pos2-pos-2); + } + } + this->CurrentPositionInFile = buffer.npos; + return ""; +} + +/** Query for the cpu status */ +int SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() +{ + this->NumberOfLogicalCPU = 0; + this->NumberOfPhysicalCPU = 0; + kwsys_stl::string buffer; + + FILE *fd = fopen("/proc/cpuinfo", "r" ); + if ( !fd ) + { + kwsys_ios::cout << "Problem opening /proc/cpuinfo" << kwsys_ios::endl; + return 0; + } + + size_t fileSize = 0; + while(!feof(fd)) + { + buffer += static_cast(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; + kwsys_stl::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) + kwsys_stl::string cores = + this->ExtractValueFromCpuInfoFile(buffer,"cpu cores"); + int numberOfCoresPerCPU=atoi(cores.c_str()); + this->NumberOfPhysicalCPU=static_cast( + numberOfCoresPerCPU*(maxId+1)); + +#else // __CYGWIN__ + // does not have "physical id" entries, neither "cpu cores" + // this has to be fixed for hyper-threading. + kwsys_stl::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 + // beter 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 proc + kwsys_stl::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer,"cpu MHz"); + this->CPUSpeedInMHz = static_cast(atof(CPUSpeed.c_str())); + + // Chip family + this->ChipID.Family = atoi(this->ExtractValueFromCpuInfoFile(buffer,"cpu family").c_str()); + + // Chip Vendor + this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer,"vendor_id"); + this->FindManufacturer(); + + // Chip Model + this->ChipID.Model = atoi(this->ExtractValueFromCpuInfoFile(buffer,"model").c_str()); + this->RetrieveClassicalCPUIdentity(); + + // L1 Cache size + kwsys_stl::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer,"cache size"); + pos = cacheSize.find(" KB"); + if(pos!=cacheSize.npos) + { + cacheSize = cacheSize.substr(0,pos); + } + this->Features.L1CacheSize = atoi(cacheSize.c_str()); + return 1; +} + +/** Query for the memory status */ +int SystemInformationImplementation::QueryMemory() +{ + this->TotalVirtualMemory = 0; + this->TotalPhysicalMemory = 0; + this->AvailableVirtualMemory = 0; + this->AvailablePhysicalMemory = 0; +#ifdef __CYGWIN__ + return 0; +#elif defined(_WIN32) +#if _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(TotalVirtual); + tp = ms.MEM_VAL(TotalPhys); + av = ms.MEM_VAL(AvailVirtual); + 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 1; +#elif 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 ) + { + kwsys_ios::cout << "Problem calling uname(): " << strerror(errno) << kwsys_ios::endl; + return 0; + } + + if( unameInfo.release!=0 && 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 ) + { + kwsys_ios::cout << "Problem opening /proc/meminfo" << kwsys_ios::endl; + return 0; + } + + 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, 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 + { + kwsys_ios::cout << "Problem parsing /proc/meminfo" << kwsys_ios::endl; + fclose(fd); + return 0; + } + } + else + { + // /proc/meminfo format for kernel older than 2.6.x + + unsigned long temp; + unsigned long cachedMem; + unsigned long buffersMem; + char *r=fgets(buffer, sizeof(buffer), fd); // Skip "total: used:..." + 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 + { + kwsys_ios::cout << "Problem parsing /proc/meminfo" << kwsys_ios::endl; + fclose(fd); + return 0; + } + } + fclose( fd ); + return 1; +#elif 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) + { + 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) + { + 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 1; + } + } + return 0; +#else + return 0; +#endif + + +} + +/** */ +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 */ +LongLong SystemInformationImplementation::GetCyclesDifference (DELAY_FUNC DelayFunction, + unsigned int uiParameter) +{ +#if 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(cores_per_package); +#else + unsigned int Regebx = 0; +#if USE_ASM_INSTRUCTIONS + if (!this->IsHyperThreadingSupported()) + { + return static_cast(1); // HT not supported + } + __asm + { + mov eax, 1 + cpuid + mov Regebx, ebx + } +#endif + return static_cast ((Regebx & NUM_LOGICAL_BITS) >> 16); +#endif +} + + +/** Works only for windows */ +unsigned int SystemInformationImplementation::IsHyperThreadingSupported() +{ +#if USE_ASM_INSTRUCTIONS + unsigned int Regedx = 0, + Regeax = 0, + VendorId[3] = {0, 0, 0}; + __try // Verify cpuid instruction is supported + { + __asm + { + xor eax, eax // call cpuid with eax = 0 + cpuid // Get vendor id string + mov VendorId, ebx + mov VendorId + 4, edx + mov VendorId + 8, ecx + + mov eax, 1 // call cpuid with eax = 1 + cpuid + mov Regeax, eax // eax contains family processor type + mov Regedx, edx // edx has info about the availability of hyper-Threading + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return(0); // cpuid is unavailable + } + + if (((Regeax & FAMILY_ID) == PENTIUM4_ID) || (Regeax & EXT_FAMILY_ID)) + { + if (VendorId[0] == 'uneG') + { + if (VendorId[1] == 'Ieni') + { + if (VendorId[2] == 'letn') + { + return(Regedx & HT_BIT); // Genuine Intel with hyper-Threading technology + } + } + } + } +#endif + + return 0; // Not genuine Intel processor +} + + +/** Return the APIC Id. Works only for windows. */ +unsigned char SystemInformationImplementation::GetAPICId() +{ + unsigned int Regebx = 0; + +#if USE_ASM_INSTRUCTIONS + if (!this->IsHyperThreadingSupported()) + { + return static_cast(-1); // HT not supported + } // Logical processor = 1 + __asm + { + mov eax, 1 + cpuid + mov Regebx, ebx + } +#endif + + return static_cast((Regebx & 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__) + 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 ) + { + 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(struct xsw_usage); + 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); + 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; + char retBuf[32]; + ::memset(retBuf, 0, 32); + len = 32; + err = sysctlbyname("hw.machine", &retBuf, &len, NULL, 0); + kwsys_stl::string machineBuf(retBuf); + if (machineBuf.find_first_of("Power") != kwsys_stl::string::npos) + { + this->ChipID.Vendor = "IBM"; + len = 4; + err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, NULL, 0); + 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); + + char retBuf[128]; + ::memset(retBuf, 0, 128); + len = 128; + err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, NULL, 0); + // Chip Vendor + this->ChipID.Vendor = retBuf; + this->FindManufacturer(); + + ::memset(retBuf, 0, 128); + err = + sysctlbyname("machdep.cpu.brand_string", + retBuf, &len, NULL, 0); + this->ChipID.ProcessorName = retBuf; + + // Chip Model + len = sizeof(value); + err = sysctlbyname("machdep.cpu.model", &value, &len, NULL, 0); + this->ChipID.Model = static_cast< int >( value ); + } + // Cache size + len = sizeof(value); + err = sysctlbyname("hw.l1icachesize", &value, &len, NULL, 0); + this->Features.L1CacheSize = static_cast< int >( 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 */ +kwsys_stl::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 */ +kwsys_stl::string SystemInformationImplementation::RunProcess(kwsys_stl::vector args) +{ + kwsys_stl::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; + + while(kwsysProcess_WaitForData(gp,&data,&length,&timeout)) // wait for 1s + { + for(int i=0;i args; + args.clear(); + args.push_back("kstat"); + args.push_back("-p"); + + kwsys_stl::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 && posRunProcess(args); + + kwsys_stl::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') + { + kwsys_stl::string val = value; + value = buffer[i]; + value += val; + } + } + return value; +} + + +/** Querying for system information from Solaris */ +bool SystemInformationImplementation::QuerySolarisInfo() +{ + // Parse values + this->NumberOfPhysicalCPU = static_cast( + atoi(this->ParseValueFromKStat("-n syste_misc -s ncpus").c_str())); + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + + if(this->NumberOfPhysicalCPU!=0) + { + this->NumberOfLogicalCPU /= this->NumberOfPhysicalCPU; + } + + this->CPUSpeedInMHz = static_cast(atoi(this->ParseValueFromKStat("-s clock_MHz").c_str())); + + // Chip family + this->ChipID.Family = 0; + + // Chip Vendor + this->ChipID.Vendor = "Sun"; + this->FindManufacturer(); + + // Chip Model + this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type"); + this->ChipID.Model = 0; + + // Cache size + this->Features.L1CacheSize = 0; + this->Features.L2CacheSize = 0; + + char* tail; + unsigned long totalMemory = + strtoul(this->ParseValueFromKStat("-s physmem").c_str(),&tail,0); + this->TotalPhysicalMemory = totalMemory/1024; + this->TotalPhysicalMemory *= 8192; + this->TotalPhysicalMemory /= 1024; + + // Undefined values (for now at least) + this->TotalVirtualMemory = 0; + this->AvailablePhysicalMemory = 0; + this->AvailableVirtualMemory = 0; + + return true; +} + + +/** Querying for system information from Haiku OS */ +bool SystemInformationImplementation::QueryHaikuInfo() +{ +#if defined(__HAIKU__) + + system_info info; + get_system_info(&info); + + this->NumberOfPhysicalCPU = info.cpu_count; + this->CPUSpeedInMHz = info.cpu_clock_speed / 1000000.0F; + + // 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__) + kwsys_stl::string buffer; + kwsys_stl::vector 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::QueryQNXProcessor() +{ +#if defined(__QNX__) + // the output on my QNX 6.4.1 looks like this: + // Processor1: 686 Pentium II Stepping 3 2175MHz FPU + kwsys_stl::string buffer; + kwsys_stl::vector 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 +} + +/** Query the operating system information */ +bool SystemInformationImplementation::QueryOSInformation() +{ +#if defined(_WIN32) + + this->OSName = "Windows"; + + OSVERSIONINFOEX osvi; + BOOL bIsWindows64Bit; + BOOL bOsVersionInfoEx; + char operatingSystem[256]; + + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + ZeroMemory (&osvi, sizeof (OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX); + bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi); + if (!bOsVersionInfoEx) + { + osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + if (!GetVersionEx ((OSVERSIONINFO *) &osvi)) + { + return false; + } + } + + 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, "%s (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF); + this->OSVersion = operatingSystem; + } + else +#endif // VER_NT_WORKSTATION + { + HKEY hKey; + char szProductType[80]; + DWORD dwBufLen; + + // Query the registry to retrieve information. + RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_QUERY_VALUE, &hKey); + RegQueryValueEx (hKey, "ProductType", NULL, NULL, (LPBYTE) szProductType, &dwBufLen); + RegCloseKey (hKey); + + if (lstrcmpi ("WINNT", szProductType) == 0) + { + this->OSRelease += " Professional"; + } + if (lstrcmpi ("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 (lstrcmpi ("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 %s (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 = LoadLibrary ("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,"%s (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->CallSwVers(); +#endif + +#endif + + return true; + +} + + +void SystemInformationImplementation::CallSwVers() +{ +#ifdef __APPLE__ + kwsys_stl::string output; + kwsys_stl::vector args; + args.clear(); + + args.push_back("sw_vers"); + args.push_back("-productName"); + args.push_back(0); + output = this->RunProcess(args); + this->TrimNewline(output); + this->OSName = output; + args.clear(); + + args.push_back("sw_vers"); + args.push_back("-productVersion"); + args.push_back(0); + output = this->RunProcess(args); + this->TrimNewline(output); + this->OSRelease = output; + args.clear(); + + args.push_back("sw_vers"); + args.push_back("-buildVersion"); + args.push_back(0); + output = this->RunProcess(args); + this->TrimNewline(output); + this->OSVersion = output; +#endif +} + + +void SystemInformationImplementation::TrimNewline(kwsys_stl::string& output) +{ + // remove \r + kwsys_stl::string::size_type pos=0; + while((pos = output.find("\r", pos)) != kwsys_stl::string::npos) + { + output.erase(pos); + } + + // remove \n + pos = 0; + while((pos = output.find("\n", pos)) != kwsys_stl::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/SystemInformation.hxx.in b/SystemInformation.hxx.in new file mode 100644 index 000000000..b6ebe6aee --- /dev/null +++ b/SystemInformation.hxx.in @@ -0,0 +1,88 @@ +/*============================================================================ + 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 + + +/* Define these macros temporarily to keep the code readable. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsys_stl @KWSYS_NAMESPACE@_stl +# define kwsys_ios @KWSYS_NAMESPACE@_ios +#endif +#include <@KWSYS_NAMESPACE@/stl/string> +#include /* size_t */ + +namespace @KWSYS_NAMESPACE@ +{ + + +// forward declare the implementation class +class SystemInformationImplementation; + +class @KWSYS_NAMESPACE@_EXPORT SystemInformation +{ + +public: + SystemInformation (); + ~SystemInformation (); + + const char * GetVendorString(); + const char * GetVendorID(); + kwsys_stl::string GetTypeID(); + kwsys_stl::string GetFamilyID(); + kwsys_stl::string GetModelID(); + kwsys_stl::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(); + 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(); + + /** Run the different checks */ + void RunCPUCheck(); + void RunOSCheck(); + void RunMemoryCheck(); +private: + SystemInformationImplementation* Implementation; + +}; +} // namespace @KWSYS_NAMESPACE@ + +/* Undefine temporary macros. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsys_stl +# undef kwsys_ios +#endif + +#endif diff --git a/SystemTools.cxx b/SystemTools.cxx new file mode 100644 index 000000000..8ab580f0e --- /dev/null +++ b/SystemTools.cxx @@ -0,0 +1,4860 @@ +/*============================================================================ + 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(RegularExpression.hxx) +#include KWSYS_HEADER(SystemTools.hxx) +#include KWSYS_HEADER(Directory.hxx) + +#include KWSYS_HEADER(ios/iostream) +#include KWSYS_HEADER(ios/fstream) +#include KWSYS_HEADER(ios/sstream) + +#include KWSYS_HEADER(stl/set) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "SystemTools.hxx.in" +# include "Directory.hxx.in" +# include "kwsys_ios_iostream.h.in" +# include "kwsys_ios_fstream.h.in" +# include "kwsys_ios_sstream.h.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 +#include +#ifdef __QNX__ +# include /* for malloc/free on QNX */ +#endif +#include +#include +#include +#include +#include + +// support for realpath call +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#ifndef __VMS +#include +#include +#endif +#include /* sigprocmask */ +#endif + +// Windows API. +#if defined(_WIN32) +# include +#elif defined (__CYGWIN__) +# include +# undef _WIN32 +#endif + +#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H +# if defined(_WIN32) +extern __declspec(dllimport) char **environ; +# else +extern char **environ; +# endif +#endif + +#ifdef __CYGWIN__ +extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32_path); +#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 +#else +#include +#endif + + +// This is a hack to prevent warnings about these functions being +// declared but not referenced. +#if defined(__sgi) && !defined(__GNUC__) +# include +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 +#include +#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 +#define _mkdir mkdir +#define _rmdir rmdir +#define _getcwd getcwd +#define _chdir chdir +#endif + +#if defined(__HAIKU__) +#include +#include +#endif + +#if defined(__BEOS__) && !defined(__ZETA__) && !defined(__HAIKU__) +#include +#include + +// 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 + +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__MINGW32__)) +inline int Mkdir(const char* dir) +{ + return _mkdir(dir); +} +inline int Rmdir(const char* dir) +{ + return _rmdir(dir); +} +inline const char* Getcwd(char* buf, unsigned int len) +{ + const char* ret = _getcwd(buf, len); + if(!ret) + { + fprintf(stderr, "No current working directory.\n"); + abort(); + } + // make sure the drive letter is capital + if(strlen(buf) > 1 && buf[1] == ':') + { + buf[0] = toupper(buf[0]); + } + return ret; +} +inline int Chdir(const char* dir) +{ + #if defined(__BORLANDC__) + return chdir(dir); + #else + return _chdir(dir); + #endif +} +inline void Realpath(const char *path, kwsys_stl::string & resolved_path) +{ + char *ptemp; + char fullpath[MAX_PATH]; + if( GetFullPathName(path, sizeof(fullpath), fullpath, &ptemp) ) + { + resolved_path = fullpath; + KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path); + } + else + { + resolved_path = path; + } +} +#else +#include +#include +#include +inline int Mkdir(const char* dir) +{ + return mkdir(dir, 00777); +} +inline int Rmdir(const char* dir) +{ + return rmdir(dir); +} +inline const char* Getcwd(char* buf, unsigned int len) +{ + const char* ret = getcwd(buf, len); + if(!ret) + { + fprintf(stderr, "No current working directory\n"); + abort(); + } + return ret; +} + +inline int Chdir(const char* dir) +{ + return chdir(dir); +} +inline void Realpath(const char *path, kwsys_stl::string & resolved_path) +{ + char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH]; + + char *ret = realpath(path, resolved_name); + if(ret) + { + resolved_path = ret; + } + 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 kwsys_stl::map +{ +}; + +// adds the elements of the env variable path to the arg passed in +void SystemTools::GetPath(kwsys_stl::vector& path, const char* env) +{ +#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; + } + + kwsys_stl::string pathEnv = cpathEnv; + + // A hack to make the below algorithm work. + if(!pathEnv.empty() && pathEnv[pathEnv.length()-1] != pathSep[0]) + { + pathEnv += pathSep; + } + kwsys_stl::string::size_type start =0; + bool done = false; + while(!done) + { + kwsys_stl::string::size_type endpos = pathEnv.find(pathSep, start); + if(endpos != kwsys_stl::string::npos) + { + path.push_back(pathEnv.substr(start, endpos-start)); + start = endpos+1; + } + else + { + done = true; + } + } + for(kwsys_stl::vector::iterator i = path.begin(); + i != path.end(); ++i) + { + SystemTools::ConvertToUnixSlashes(*i); + } +} + +const char* SystemTools::GetEnv(const char* key) +{ + return getenv(key); +} + +bool SystemTools::GetEnv(const char* key, kwsys_stl::string& result) +{ + const char* v = getenv(key); + if(v) + { + result = v; + return true; + } + else + { + return false; + } +} + +//---------------------------------------------------------------------------- + +#if defined(__CYGWIN__) || defined(__GLIBC__) +# define KWSYS_PUTENV_NAME /* putenv("A") removes A. */ +#elif defined(_WIN32) +# define KWSYS_PUTENV_EMPTY /* putenv("A=") removes A. */ +#endif + +#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 char* env) +{ + if(const char* eq = strchr(env, '=')) + { + std::string name(env, eq-env); + unsetenv(name.c_str()); + } + else + { + unsetenv(env); + } + return 0; +} + +#elif defined(KWSYS_PUTENV_EMPTY) || defined(KWSYS_PUTENV_NAME) +/* putenv("A=") or putenv("A") removes A from the environment. */ +static int kwsysUnPutEnv(const char* env) +{ + int err = 0; + const char* eq = strchr(env, '='); + size_t const len = eq? (size_t)(eq-env) : strlen(env); +# ifdef KWSYS_PUTENV_EMPTY + size_t const sz = len + 2; +# else + size_t const sz = len + 1; +# endif + char local_buf[256]; + char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf; + if(!buf) + { + return -1; + } + strncpy(buf, env, len); +# ifdef KWSYS_PUTENV_EMPTY + buf[len] = '='; + buf[len+1] = 0; + if(putenv(buf) < 0) + { + err = errno; + } +# else + buf[len] = 0; + if(putenv(buf) < 0 && errno != EINVAL) + { + err = errno; + } +# endif + if(buf != local_buf) + { + free(buf); + } + if(err) + { + errno = err; + return -1; + } + return 0; +} + +#else +/* Manipulate the "environ" global directly. */ +static int kwsysUnPutEnv(const char* env) +{ + const char* eq = strchr(env, '='); + size_t const len = eq? (size_t)(eq-env) : strlen(env); + int in = 0; + int out = 0; + while(environ[in]) + { + if(strlen(environ[in]) > len && + environ[in][len] == '=' && + strncmp(env, 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 char* env) +{ + if(const char* eq = strchr(env, '=')) + { + std::string name(env, eq-env); + return setenv(name.c_str(), eq+1, 1) == 0; + } + else + { + return kwsysUnPutEnv(env) == 0; + } +} + +bool SystemTools::UnPutEnv(const char* 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 + +/* Order by environment key only (VAR from VAR=VALUE). */ +struct kwsysEnvCompare +{ + bool operator() (const char* l, const char* r) const + { + 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; + } + } +}; + +class kwsysEnv: public kwsys_stl::set +{ + class Free + { + const char* Env; + public: + Free(const char* env): Env(env) {} + ~Free() { free(const_cast(this->Env)); } + }; +public: + typedef kwsys_stl::set derived; + ~kwsysEnv() + { + for(derived::iterator i = this->begin(); i != this->end(); ++i) + { + kwsysUnPutEnv(*i); + free(const_cast(*i)); + } + } + const char* Release(const char* env) + { + const char* old = 0; + derived::iterator i = this->find(env); + if(i != this->end()) + { + old = *i; + this->erase(i); + } + return old; + } + bool Put(const char* env) + { + Free oldEnv(this->Release(env)); + static_cast(oldEnv); + char* newEnv = strdup(env); + this->insert(newEnv); + return putenv(newEnv) == 0; + } + bool UnPut(const char* env) + { + Free oldEnv(this->Release(env)); + static_cast(oldEnv); + return kwsysUnPutEnv(env) == 0; + } +}; + +static kwsysEnv kwsysEnvInstance; + +bool SystemTools::PutEnv(const char* env) +{ + return kwsysEnvInstance.Put(env); +} + +bool SystemTools::UnPutEnv(const char* env) +{ + return kwsysEnvInstance.UnPut(env); +} + +#endif + +//---------------------------------------------------------------------------- + +const char* SystemTools::GetExecutableExtension() +{ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS) + return ".exe"; +#else + return ""; +#endif +} + + +bool SystemTools::MakeDirectory(const char* path) +{ + if(!path) + { + return false; + } + if(SystemTools::FileExists(path)) + { + return true; + } + kwsys_stl::string dir = path; + if(dir.size() == 0) + { + return false; + } + SystemTools::ConvertToUnixSlashes(dir); + + kwsys_stl::string::size_type pos = dir.find(':'); + if(pos == kwsys_stl::string::npos) + { + pos = 0; + } + kwsys_stl::string topdir; + while((pos = dir.find('/', pos)) != kwsys_stl::string::npos) + { + topdir = dir.substr(0, pos); + Mkdir(topdir.c_str()); + pos++; + } + if(dir[dir.size()-1] == '/') + { + topdir = dir.substr(0, dir.size()); + } + else + { + topdir = dir; + } + if(Mkdir(topdir.c_str()) != 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(kwsys_stl::string& source, + const char* replace, + const char* with) +{ + const char *src = source.c_str(); + char *searchPos = const_cast(strstr(src,replace)); + + // get out quick if string is not found + if (!searchPos) + { + return; + } + + // perform replacements until done + size_t replaceSize = strlen(replace); + // do while hangs if replaceSize is 0 + if(replaceSize == 0) + { + return; + } + 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 DWORD SystemToolsMakeRegistryMode(DWORD mode, + SystemTools::KeyWOW64 view) +{ + // only add the modes when on a system that supports Wow64. + static FARPROC wow64p = GetProcAddress(GetModuleHandle("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 + +// 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 char *key, kwsys_stl::string &value, + KeyWOW64 view) +{ + bool valueset = false; + kwsys_stl::string primary = key; + kwsys_stl::string second; + kwsys_stl::string valuename; + + size_t start = primary.find("\\"); + if (start == kwsys_stl::string::npos) + { + return false; + } + + size_t valuenamepos = primary.find(";"); + if (valuenamepos != kwsys_stl::string::npos) + { + valuename = primary.substr(valuenamepos+1); + } + + second = primary.substr(start+1, valuenamepos-start-1); + primary = primary.substr(0, start); + + HKEY primaryKey = HKEY_CURRENT_USER; + 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; + } + + HKEY hKey; + if(RegOpenKeyEx(primaryKey, + second.c_str(), + 0, + SystemToolsMakeRegistryMode(KEY_READ, view), + &hKey) != ERROR_SUCCESS) + { + return false; + } + else + { + DWORD dwType, dwSize; + dwSize = 1023; + char data[1024]; + if(RegQueryValueEx(hKey, + (LPTSTR)valuename.c_str(), + NULL, + &dwType, + (BYTE *)data, + &dwSize) == ERROR_SUCCESS) + { + if (dwType == REG_SZ) + { + value = data; + valueset = true; + } + else if (dwType == REG_EXPAND_SZ) + { + char expanded[1024]; + DWORD dwExpandedSize = sizeof(expanded)/sizeof(expanded[0]); + if(ExpandEnvironmentStrings(data, expanded, dwExpandedSize)) + { + value = expanded; + valueset = true; + } + } + } + + RegCloseKey(hKey); + } + + return valueset; +} +#else +bool SystemTools::ReadRegistryValue(const char *, kwsys_stl::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 char *key, const char *value, + KeyWOW64 view) +{ + kwsys_stl::string primary = key; + kwsys_stl::string second; + kwsys_stl::string valuename; + + size_t start = primary.find("\\"); + if (start == kwsys_stl::string::npos) + { + return false; + } + + size_t valuenamepos = primary.find(";"); + if (valuenamepos != kwsys_stl::string::npos) + { + valuename = primary.substr(valuenamepos+1); + } + + second = primary.substr(start+1, valuenamepos-start-1); + primary = primary.substr(0, start); + + HKEY primaryKey = HKEY_CURRENT_USER; + 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; + } + + HKEY hKey; + DWORD dwDummy; + char lpClass[] = ""; + if(RegCreateKeyEx(primaryKey, + second.c_str(), + 0, + lpClass, + REG_OPTION_NON_VOLATILE, + SystemToolsMakeRegistryMode(KEY_WRITE, view), + NULL, + &hKey, + &dwDummy) != ERROR_SUCCESS) + { + return false; + } + + if(RegSetValueEx(hKey, + (LPTSTR)valuename.c_str(), + 0, + REG_SZ, + (CONST BYTE *)value, + (DWORD)(strlen(value) + 1)) == ERROR_SUCCESS) + { + return true; + } + return false; +} +#else +bool SystemTools::WriteRegistryValue(const char *, const char *, 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 char *key, KeyWOW64 view) +{ + kwsys_stl::string primary = key; + kwsys_stl::string second; + kwsys_stl::string valuename; + + size_t start = primary.find("\\"); + if (start == kwsys_stl::string::npos) + { + return false; + } + + size_t valuenamepos = primary.find(";"); + if (valuenamepos != kwsys_stl::string::npos) + { + valuename = primary.substr(valuenamepos+1); + } + + second = primary.substr(start+1, valuenamepos-start-1); + primary = primary.substr(0, start); + + HKEY primaryKey = HKEY_CURRENT_USER; + 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; + } + + HKEY hKey; + if(RegOpenKeyEx(primaryKey, + 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 char *, KeyWOW64) +{ + return false; +} +#endif + +bool SystemTools::SameFile(const char* file1, const char* file2) +{ +#ifdef _WIN32 + HANDLE hFile1, hFile2; + + hFile1 = CreateFile( file1, + GENERIC_READ, + FILE_SHARE_READ , + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + hFile2 = CreateFile( file2, + 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, &fileStat1) == 0 && stat(file2, &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 +} + +//---------------------------------------------------------------------------- +#if defined(_WIN32) || defined(__CYGWIN__) +static bool WindowsFileExists(const char* filename) +{ + WIN32_FILE_ATTRIBUTE_DATA fd; + return GetFileAttributesExA(filename, GetFileExInfoStandard, &fd) != 0; +} +#endif + +//---------------------------------------------------------------------------- +bool SystemTools::FileExists(const char* filename) +{ + if(!(filename && *filename)) + { + return false; + } +#if defined(__CYGWIN__) + // Convert filename to native windows path if possible. + char winpath[MAX_PATH]; + if(SystemTools::PathCygwinToWin32(filename, winpath)) + { + return WindowsFileExists(winpath); + } + return access(filename, R_OK) == 0; +#elif defined(_WIN32) + return WindowsFileExists(filename); +#else + return access(filename, R_OK) == 0; +#endif +} + +//---------------------------------------------------------------------------- +bool SystemTools::FileExists(const char* 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; +} + +//---------------------------------------------------------------------------- +#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 + { + cygwin_conv_to_win32_path(path, win32_path); + SystemToolsTranslationMap::value_type entry(path, win32_path); + SystemTools::Cyg2Win32Map->insert(entry); + } + return win32_path[0] != 0; +} +#endif + +bool SystemTools::Touch(const char* filename, bool create) +{ + if(create && !SystemTools::FileExists(filename)) + { + FILE* file = fopen(filename, "a+b"); + if(file) + { + fclose(file); + return true; + } + return false; + } +#ifdef _MSC_VER +#define utime _utime +#define utimbuf _utimbuf +#endif + struct stat fromStat; + if(stat(filename, &fromStat) < 0) + { + return false; + } + struct utimbuf buf; + buf.actime = fromStat.st_atime; + buf.modtime = static_cast(SystemTools::GetTime()); + if(utime(filename, &buf) < 0) + { + return false; + } + return true; +} + +bool SystemTools::FileTimeCompare(const char* f1, const char* 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, &s1) != 0) + { + return false; + } + struct stat s2; + if(stat(f2, &s2) != 0) + { + return false; + } +# if KWSYS_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; + } +# 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(!GetFileAttributesEx(f1, GetFileExInfoStandard, &f1d)) + { + return false; + } + if(!GetFileAttributesEx(f2, 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) +kwsys_stl::string SystemTools::Capitalized(const kwsys_stl::string& s) +{ + kwsys_stl::string n; + if(s.size() == 0) + { + return n; + } + n.resize(s.size()); + n[0] = static_cast(toupper(s[0])); + for (size_t i = 1; i < s.size(); i++) + { + n[i] = static_cast(tolower(s[i])); + } + return n; +} + +// Return capitalized words +kwsys_stl::string SystemTools::CapitalizedWords(const kwsys_stl::string& s) +{ + kwsys_stl::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(toupper(s[i])); + } + } + return n; +} + +// Return uncapitalized words +kwsys_stl::string SystemTools::UnCapitalizedWords(const kwsys_stl::string& s) +{ + kwsys_stl::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(tolower(s[i])); + } + } + return n; +} + +// only works for words with at least two letters +kwsys_stl::string SystemTools::AddSpaceBetweenCapitalizedWords( + const kwsys_stl::string& s) +{ + kwsys_stl::string n; + if (s.size()) + { + 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 +kwsys_stl::string SystemTools::LowerCase(const kwsys_stl::string& s) +{ + kwsys_stl::string n; + n.resize(s.size()); + for (size_t i = 0; i < s.size(); i++) + { + n[i] = static_cast(tolower(s[i])); + } + return n; +} + +// Return a lower case string +kwsys_stl::string SystemTools::UpperCase(const kwsys_stl::string& s) +{ + kwsys_stl::string n; + n.resize(s.size()); + for (size_t i = 0; i < s.size(); i++) + { + n[i] = static_cast(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 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 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 +kwsys_stl::string SystemTools::CropString(const kwsys_stl::string& s, + size_t max_len) +{ + if (!s.size() || max_len == 0 || max_len >= s.size()) + { + return s; + } + + kwsys_stl::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), kwsys_stl::string::npos); + + if (max_len > 2) + { + n[middle] = '.'; + if (max_len > 3) + { + n[middle - 1] = '.'; + if (max_len > 4) + { + n[middle + 1] = '.'; + } + } + } + + return n; +} + +//---------------------------------------------------------------------------- +kwsys_stl::vector SystemTools::SplitString(const char* p, char sep, bool isPath) +{ + kwsys_stl::string path = p; + kwsys_stl::vector paths; + if(path.empty()) + { + return paths; + } + if(isPath && path[0] == '/') + { + path.erase(path.begin()); + paths.push_back("/"); + } + kwsys_stl::string::size_type pos1 = 0; + kwsys_stl::string::size_type pos2 = path.find(sep, pos1+1); + while(pos2 != kwsys_stl::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(va_arg(ap, double)); + } break; + default: + { + // Assume the argument contributes no more than 64 characters. + length += 64; + + // Eat the argument. + static_cast(va_arg(ap, int)); + } break; + } + } + + // Move past the characters just tested. + ++cur; + } + } + + return static_cast(length); +} + +kwsys_stl::string SystemTools::EscapeChars( + const char *str, + const char *chars_to_escape, + char escape_char) +{ + kwsys_stl::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(kwsys_stl::string& path) +{ + kwsys_stl::string::size_type rootEnd = path.find(":["); + kwsys_stl::string::size_type pathEnd = path.find("]"); + if(rootEnd != path.npos) + { + kwsys_stl::string root = path.substr(0, rootEnd); + kwsys_stl::string pathPart = path.substr(rootEnd+2, pathEnd - rootEnd-2); + const char* pathCString = pathPart.c_str(); + const char* pos0 = pathCString; + for (kwsys_stl::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(kwsys_stl::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 (kwsys_stl::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] == '~') + { + kwsys_stl::string::size_type idx = path.find_first_of("/\0"); + kwsys_stl::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(); + if(path.size() > 1 && *(pathCString+(path.size()-1)) == '/') + { + // if it is c:/ then do not remove the trailing slash + if(!((path.size() == 3 && pathCString[1] == ':'))) + { + path = path.substr(0, path.size()-1); + } + } + } +} + +// change // to /, and escape any spaces in the path +kwsys_stl::string SystemTools::ConvertToUnixOutputPath(const char* path) +{ + kwsys_stl::string ret = path; + + // remove // except at the beginning might be a cygwin drive + kwsys_stl::string::size_type pos=1; + while((pos = ret.find("//", pos)) != kwsys_stl::string::npos) + { + ret.erase(pos, 1); + } + // escape spaces and () in the path + if(ret.find_first_of(" ") != kwsys_stl::string::npos) + { + kwsys_stl::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; +} + +kwsys_stl::string SystemTools::ConvertToOutputPath(const char* path) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return SystemTools::ConvertToWindowsOutputPath(path); +#else + return SystemTools::ConvertToUnixOutputPath(path); +#endif +} + +// remove double slashes not at the start +kwsys_stl::string SystemTools::ConvertToWindowsOutputPath(const char* path) +{ + kwsys_stl::string ret; + // make it big enough for all of path and double quotes + ret.reserve(strlen(path)+3); + // put path into the string + ret.assign(path); + ret = path; + kwsys_stl::string::size_type pos = 0; + // first convert all of the slashes + while((pos = ret.find('/', pos)) != kwsys_stl::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)) != kwsys_stl::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(' ') != kwsys_stl::string::npos + && ret[0] != '\"') + { + ret.insert(static_cast(0), + static_cast(1), '\"'); + ret.append(1, '\"'); + } + return ret; +} + +bool SystemTools::CopyFileIfDifferent(const char* source, + const char* destination) +{ + // special check for a destination that is a directory + // FilesDiffer does not handle file to directory compare + if(SystemTools::FileIsDirectory(destination)) + { + kwsys_stl::string new_destination = destination; + SystemTools::ConvertToUnixSlashes(new_destination); + new_destination += '/'; + kwsys_stl::string source_name = source; + new_destination += SystemTools::GetFilenameName(source_name); + if(SystemTools::FilesDiffer(source, new_destination.c_str())) + { + 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 char* source, + const char* destination) +{ + struct stat statSource; + if (stat(source, &statSource) != 0) + { + return true; + } + + struct stat statDestination; + if (stat(destination, &statDestination) != 0) + { + return true; + } + + if(statSource.st_size != statDestination.st_size) + { + return true; + } + + if(statSource.st_size == 0) + { + return false; + } + +#if defined(_WIN32) || defined(__CYGWIN__) + kwsys_ios::ifstream finSource(source, (kwsys_ios::ios::binary | + kwsys_ios::ios::in)); + kwsys_ios::ifstream finDestination(destination, (kwsys_ios::ios::binary | + kwsys_ios::ios::in)); +#else + kwsys_ios::ifstream finSource(source); + kwsys_ios::ifstream finDestination(destination); +#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]; + off_t nleft = statSource.st_size; + while(nleft > 0) + { + // Read a block from each file. + kwsys_ios::streamsize nnext = (nleft > KWSYS_ST_BUFFER)? KWSYS_ST_BUFFER : static_cast(nleft); + finSource.read(source_buf, nnext); + finDestination.read(dest_buf, nnext); + + // If either failed to read assume they are different. + if(static_cast(finSource.gcount()) != nnext || + static_cast(finDestination.gcount()) != nnext) + { + return true; + } + + // If this block differs the file differs. + if(memcmp(static_cast(source_buf), + static_cast(dest_buf), + static_cast(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 char* source, const char* 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); + + 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. + + kwsys_stl::string new_destination; + if(SystemTools::FileExists(destination) && + SystemTools::FileIsDirectory(destination)) + { + new_destination = destination; + SystemTools::ConvertToUnixSlashes(new_destination); + new_destination += '/'; + kwsys_stl::string source_name = source; + new_destination += SystemTools::GetFilenameName(source_name); + destination = new_destination.c_str(); + } + + // Create destination directory + + kwsys_stl::string destination_dir = destination; + destination_dir = SystemTools::GetFilenamePath(destination_dir); + SystemTools::MakeDirectory(destination_dir.c_str()); + + // Open files + +#if defined(_WIN32) || defined(__CYGWIN__) + kwsys_ios::ifstream fin(source, + kwsys_ios::ios::binary | kwsys_ios::ios::in); +#else + kwsys_ios::ifstream fin(source); +#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(destination); + +#if defined(_WIN32) || defined(__CYGWIN__) + kwsys_ios::ofstream fout(destination, + kwsys_ios::ios::binary | kwsys_ios::ios::out | kwsys_ios::ios::trunc); +#else + kwsys_ios::ofstream fout(destination, + kwsys_ios::ios::out | kwsys_ios::ios::trunc); +#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()); + } + } + + // 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(destination, perm) ) + { + return false; + } + } + return true; +} + +//---------------------------------------------------------------------------- +bool SystemTools::CopyAFile(const char* source, const char* 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 char* source, const char* destination, + bool always) +{ + Directory dir; + dir.Load(source); + size_t fileNum; + if ( !SystemTools::MakeDirectory(destination) ) + { + return false; + } + for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) + { + if (strcmp(dir.GetFile(static_cast(fileNum)),".") && + strcmp(dir.GetFile(static_cast(fileNum)),"..")) + { + kwsys_stl::string fullPath = source; + fullPath += "/"; + fullPath += dir.GetFile(static_cast(fileNum)); + if(SystemTools::FileIsDirectory(fullPath.c_str())) + { + kwsys_stl::string fullDestPath = destination; + fullDestPath += "/"; + fullDestPath += dir.GetFile(static_cast(fileNum)); + if (!SystemTools::CopyADirectory(fullPath.c_str(), + fullDestPath.c_str(), + always)) + { + return false; + } + } + else + { + if(!SystemTools::CopyAFile(fullPath.c_str(), destination, always)) + { + return false; + } + } + } + } + + return true; +} + + +// return size of file; also returns zero if no file exists +unsigned long SystemTools::FileLength(const char* filename) +{ + struct stat fs; + if (stat(filename, &fs) != 0) + { + return 0; + } + else + { + return static_cast(fs.st_size); + } +} + +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 char* filename) +{ + struct stat fs; + if (stat(filename, &fs) != 0) + { + return 0; + } + else + { + return static_cast(fs.st_mtime); + } +} + +// return file's creation time +long int SystemTools::CreationTime(const char* filename) +{ + struct stat fs; + if (stat(filename, &fs) != 0) + { + return 0; + } + else + { + return fs.st_ctime >= 0 ? static_cast(fs.st_ctime) : 0; + } +} + +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((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((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; +} + +kwsys_stl::string SystemTools::GetLastSystemError() +{ + int e = errno; + return strerror(e); +} + +bool SystemTools::RemoveFile(const char* source) +{ +#ifdef _WIN32 + mode_t mode; + if ( !SystemTools::GetPermissions(source, mode) ) + { + return false; + } + /* Win32 unlink is stupid --- it fails if the file is read-only */ + SystemTools::SetPermissions(source, S_IWRITE); +#endif + bool res = unlink(source) != 0 ? false : true; +#ifdef _WIN32 + if ( !res ) + { + SystemTools::SetPermissions(source, mode); + } +#endif + return res; +} + +bool SystemTools::RemoveADirectory(const char* 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; + dir.Load(source); + size_t fileNum; + for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) + { + if (strcmp(dir.GetFile(static_cast(fileNum)),".") && + strcmp(dir.GetFile(static_cast(fileNum)),"..")) + { + kwsys_stl::string fullPath = source; + fullPath += "/"; + fullPath += dir.GetFile(static_cast(fileNum)); + if(SystemTools::FileIsDirectory(fullPath.c_str()) && + !SystemTools::FileIsSymlink(fullPath.c_str())) + { + if (!SystemTools::RemoveADirectory(fullPath.c_str())) + { + return false; + } + } + else + { + if(!SystemTools::RemoveFile(fullPath.c_str())) + { + 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. + */ +kwsys_stl::string SystemTools +::FindName(const char* name, + const kwsys_stl::vector& userPaths, + bool no_system_path) +{ + // Add the system search path to our path first + kwsys_stl::vector path; + if (!no_system_path) + { + SystemTools::GetPath(path, "CMAKE_FILE_PATH"); + SystemTools::GetPath(path); + } + // now add the additional paths + { + for(kwsys_stl::vector::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(kwsys_stl::vector::iterator i = path.begin(); + i != path.end(); ++i) + { + kwsys_stl::string& p = *i; + if(p.empty() || p[p.size()-1] != '/') + { + p += "/"; + } + } + } + // now look for the file + kwsys_stl::string tryPath; + for(kwsys_stl::vector::const_iterator p = path.begin(); + p != path.end(); ++p) + { + tryPath = *p; + tryPath += name; + if(SystemTools::FileExists(tryPath.c_str())) + { + 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. + */ +kwsys_stl::string SystemTools +::FindFile(const char* name, + const kwsys_stl::vector& userPaths, + bool no_system_path) +{ + kwsys_stl::string tryPath = SystemTools::FindName(name, userPaths, no_system_path); + if(tryPath != "" && !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + // 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. + */ +kwsys_stl::string SystemTools +::FindDirectory(const char* name, + const kwsys_stl::vector& userPaths, + bool no_system_path) +{ + kwsys_stl::string tryPath = SystemTools::FindName(name, userPaths, no_system_path); + if(tryPath != "" && SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + // 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. + */ +kwsys_stl::string SystemTools::FindProgram( + const char* nameIn, + const kwsys_stl::vector& userPaths, + bool no_system_path) +{ + if(!nameIn || !*nameIn) + { + return ""; + } + kwsys_stl::string name = nameIn; + kwsys_stl::vector extensions; +#if defined (_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) + bool hasExtension = false; + // check to see if the name already has a .xxx at + // the end of it + if(name.size() > 3 && name[name.size()-4] == '.') + { + hasExtension = true; + } + // on windows try .com then .exe + if(!hasExtension) + { + extensions.push_back(".com"); + extensions.push_back(".exe"); + } +#endif + kwsys_stl::string tryPath; + + // first try with extensions if the os supports them + if(extensions.size()) + { + for(kwsys_stl::vector::iterator i = + extensions.begin(); i != extensions.end(); ++i) + { + tryPath = name; + tryPath += *i; + if(SystemTools::FileExists(tryPath.c_str()) && + !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + } + } + // now try just the name + tryPath = name; + if(SystemTools::FileExists(tryPath.c_str()) && + !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + // now construct the path + kwsys_stl::vector path; + // Add the system search path to our path. + if (!no_system_path) + { + SystemTools::GetPath(path); + } + // now add the additional paths + { + for(kwsys_stl::vector::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(kwsys_stl::vector::iterator i = path.begin(); + i != path.end(); ++i) + { + kwsys_stl::string& p = *i; + if(p.empty() || p[p.size()-1] != '/') + { + p += "/"; + } + } + } + // Try each path + for(kwsys_stl::vector::iterator p = path.begin(); + p != path.end(); ++p) + { +#ifdef _WIN32 + // Remove double quotes from the path on windows + SystemTools::ReplaceString(*p, "\"", ""); +#endif + // first try with extensions + if(extensions.size()) + { + for(kwsys_stl::vector::iterator ext + = extensions.begin(); ext != extensions.end(); ++ext) + { + tryPath = *p; + tryPath += name; + tryPath += *ext; + if(SystemTools::FileExists(tryPath.c_str()) && + !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + } + } + // now try it without them + tryPath = *p; + tryPath += name; + if(SystemTools::FileExists(tryPath.c_str()) && + !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + } + // Couldn't find the program. + return ""; +} + +kwsys_stl::string SystemTools::FindProgram( + const kwsys_stl::vector& names, + const kwsys_stl::vector& path, + bool noSystemPath) +{ + for(kwsys_stl::vector::const_iterator it = names.begin(); + it != names.end() ; ++it) + { + // Try to find the program. + kwsys_stl::string result = SystemTools::FindProgram(it->c_str(), + 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. + */ +kwsys_stl::string SystemTools +::FindLibrary(const char* name, + const kwsys_stl::vector& userPaths) +{ + // See if the executable exists as written. + if(SystemTools::FileExists(name) && + !SystemTools::FileIsDirectory(name)) + { + return SystemTools::CollapseFullPath(name); + } + + // Add the system search path to our path. + kwsys_stl::vector path; + SystemTools::GetPath(path); + // now add the additional paths + { + for(kwsys_stl::vector::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(kwsys_stl::vector::iterator i = path.begin(); + i != path.end(); ++i) + { + kwsys_stl::string& p = *i; + if(p.empty() || p[p.size()-1] != '/') + { + p += "/"; + } + } + } + kwsys_stl::string tryPath; + for(kwsys_stl::vector::const_iterator p = path.begin(); + p != path.end(); ++p) + { +#if defined(__APPLE__) + tryPath = *p; + tryPath += name; + tryPath += ".framework"; + if(SystemTools::FileExists(tryPath.c_str()) + && SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } +#endif +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) + tryPath = *p; + tryPath += name; + tryPath += ".lib"; + if(SystemTools::FileExists(tryPath.c_str()) + && !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } +#else + tryPath = *p; + tryPath += "lib"; + tryPath += name; + tryPath += ".so"; + if(SystemTools::FileExists(tryPath.c_str()) + && !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + tryPath = *p; + tryPath += "lib"; + tryPath += name; + tryPath += ".a"; + if(SystemTools::FileExists(tryPath.c_str()) + && !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + tryPath = *p; + tryPath += "lib"; + tryPath += name; + tryPath += ".sl"; + if(SystemTools::FileExists(tryPath.c_str()) + && !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + tryPath = *p; + tryPath += "lib"; + tryPath += name; + tryPath += ".dylib"; + if(SystemTools::FileExists(tryPath.c_str()) + && !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } + tryPath = *p; + tryPath += "lib"; + tryPath += name; + tryPath += ".dll"; + if(SystemTools::FileExists(tryPath.c_str()) + && !SystemTools::FileIsDirectory(tryPath.c_str())) + { + return SystemTools::CollapseFullPath(tryPath.c_str()); + } +#endif + } + + // Couldn't find the library. + return ""; +} + +kwsys_stl::string SystemTools::GetRealPath(const char* path) +{ + kwsys_stl::string ret; + Realpath(path, ret); + return ret; +} + +bool SystemTools::FileIsDirectory(const char* name) +{ + // Remove any trailing slash from the name. + char buffer[KWSYS_SYSTEMTOOLS_MAXPATH]; + size_t last = strlen(name)-1; + if(last > 0 && (name[last] == '/' || name[last] == '\\') + && strcmp(name, "/") !=0) + { + memcpy(buffer, name, last); + buffer[last] = 0; + name = buffer; + } + + // Now check the file node type. + struct stat fs; + if(stat(name, &fs) == 0) + { +#if defined( _WIN32 ) && !defined(__CYGWIN__) + return ((fs.st_mode & _S_IFDIR) != 0); +#else + return S_ISDIR(fs.st_mode); +#endif + } + else + { + return false; + } +} + +bool SystemTools::FileIsSymlink(const char* name) +{ +#if defined( _WIN32 ) + (void)name; + return false; +#else + struct stat fs; + if(lstat(name, &fs) == 0) + { + return S_ISLNK(fs.st_mode); + } + else + { + return false; + } +#endif +} + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool SystemTools::CreateSymlink(const char*, const char*) +{ + return false; +} +#else +bool SystemTools::CreateSymlink(const char* origName, const char* newName) +{ + return symlink(origName, newName) >= 0; +} +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool SystemTools::ReadSymlink(const char*, kwsys_stl::string&) +{ + return false; +} +#else +bool SystemTools::ReadSymlink(const char* newName, + kwsys_stl::string& origName) +{ + char buf[KWSYS_SYSTEMTOOLS_MAXPATH+1]; + int count = + static_cast(readlink(newName, 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 char *dir) +{ + return Chdir(dir); +} + +kwsys_stl::string SystemTools::GetCurrentWorkingDirectory(bool collapse) +{ + char buf[2048]; + const char* cwd = Getcwd(buf, 2048); + kwsys_stl::string path; + if ( cwd ) + { + path = cwd; + } + if(collapse) + { + return SystemTools::CollapseFullPath(path.c_str()); + } + return path; +} + +kwsys_stl::string SystemTools::GetProgramPath(const char* in_name) +{ + kwsys_stl::string dir, file; + SystemTools::SplitProgramPath(in_name, dir, file); + return dir; +} + +bool SystemTools::SplitProgramPath(const char* in_name, + kwsys_stl::string& dir, + kwsys_stl::string& file, + bool) +{ + dir = in_name; + file = ""; + SystemTools::ConvertToUnixSlashes(dir); + + if(!SystemTools::FileIsDirectory(dir.c_str())) + { + kwsys_stl::string::size_type slashPos = dir.rfind("/"); + if(slashPos != kwsys_stl::string::npos) + { + file = dir.substr(slashPos+1); + dir = dir.substr(0, slashPos); + } + else + { + file = dir; + dir = ""; + } + } + if(!(dir == "") && !SystemTools::FileIsDirectory(dir.c_str())) + { + kwsys_stl::string oldDir = in_name; + SystemTools::ConvertToUnixSlashes(oldDir); + dir = in_name; + return false; + } + return true; +} + +bool SystemTools::FindProgramPath(const char* argv0, + kwsys_stl::string& pathOut, + kwsys_stl::string& errorMsg, + const char* exeName, + const char* buildDir, + const char* installPrefix ) +{ + kwsys_stl::vector failures; + kwsys_stl::string self = argv0 ? argv0 : ""; + failures.push_back(self); + SystemTools::ConvertToUnixSlashes(self); + self = SystemTools::FindProgram(self.c_str()); + if(!SystemTools::FileExists(self.c_str())) + { + if(buildDir) + { + kwsys_stl::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.c_str())) + { + failures.push_back(self); + self = installPrefix; + self += "/bin/"; + self += exeName; + } + } + if(!SystemTools::FileExists(self.c_str())) + { + failures.push_back(self); + kwsys_ios::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"; + kwsys_stl::vector::iterator i; + for(i=failures.begin(); i != failures.end(); ++i) + { + msg << " \"" << i->c_str() << "\"\n"; + } + errorMsg = msg.str(); + return false; + } + pathOut = self; + return true; +} + + +kwsys_stl::string SystemTools::CollapseFullPath(const char* in_relative) +{ + return SystemTools::CollapseFullPath(in_relative, 0); +} + +void SystemTools::AddTranslationPath(const char * a, const char * b) +{ + kwsys_stl::string path_a = a; + kwsys_stl::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.c_str() ) ) + { + // 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.c_str()) && path_b.find("..") + == kwsys_stl::string::npos ) + { + // Before inserting make sure path ends with '/' + if(path_a.size() && path_a[path_a.size() -1] != '/') + { + path_a += '/'; + } + if(path_b.size() && path_b[path_b.size() -1] != '/') + { + path_b += '/'; + } + if( !(path_a == path_b) ) + { + SystemTools::TranslationMap->insert( + SystemToolsTranslationMap::value_type(path_a, path_b)); + } + } + } +} + +void SystemTools::AddKeepPath(const char* dir) +{ + kwsys_stl::string cdir; + Realpath(SystemTools::CollapseFullPath(dir).c_str(), cdir); + SystemTools::AddTranslationPath(cdir.c_str(), dir); +} + +void SystemTools::CheckTranslationPath(kwsys_stl::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: + kwsys_stl::map::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()); +} + +void +SystemToolsAppendComponents( + kwsys_stl::vector& out_components, + kwsys_stl::vector::const_iterator first, + kwsys_stl::vector::const_iterator last) +{ + for(kwsys_stl::vector::const_iterator i = first; + i != last; ++i) + { + if(*i == "..") + { + if(out_components.begin() != out_components.end()) + { + out_components.erase(out_components.end()-1, out_components.end()); + } + } + else if(!(*i == ".") && !(*i == "")) + { + out_components.push_back(*i); + } + } +} + +kwsys_stl::string SystemTools::CollapseFullPath(const char* in_path, + const char* in_base) +{ + // Collect the output path components. + kwsys_stl::vector out_components; + + // Split the input path components. + kwsys_stl::vector 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) + { + kwsys_stl::vector 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 + { + // ?? + } + } + + // 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. + kwsys_stl::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.c_str(), in_path); + + SystemTools::CheckTranslationPath(newPath); +#ifdef _WIN32 + newPath = SystemTools::GetActualCaseForPath(newPath.c_str()); + SystemTools::ConvertToUnixSlashes(newPath); +#endif + // Return the reconstructed path. + return newPath; +} + +// compute the relative path from here to there +kwsys_stl::string SystemTools::RelativePath(const char* local, const char* remote) +{ + if(!SystemTools::FileIsFullPath(local)) + { + return ""; + } + if(!SystemTools::FileIsFullPath(remote)) + { + return ""; + } + + // split up both paths into arrays of strings using / as a separator + kwsys_stl::vector localSplit = SystemTools::SplitString(local, '/', true); + kwsys_stl::vector remoteSplit = SystemTools::SplitString(remote, '/', true); + kwsys_stl::vector commonPath; // store shared parts of path in this array + kwsys_stl::vector 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].size()) + { + finalPath.push_back("../"); + } + } + // for each entry that is not common in the remote path add it + // to the final path. + for(kwsys_stl::vector::iterator vit = remoteSplit.begin(); + vit != remoteSplit.end(); ++vit) + { + if(vit->size()) + { + finalPath.push_back(*vit); + } + } + kwsys_stl::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(kwsys_stl::vector::iterator vit1 = finalPath.begin(); + vit1 != finalPath.end(); ++vit1) + { + if(relativePath.size() && relativePath[relativePath.size()-1] != '/') + { + relativePath += "/"; + } + relativePath += *vit1; + } + return relativePath; +} + +#ifdef _WIN32 +static int GetCasePathName(const kwsys_stl::string & pathIn, + kwsys_stl::string & casePath) +{ + kwsys_stl::vector path_components; + SystemTools::SplitPath(pathIn.c_str(), path_components); + if(path_components[0].empty()) // First component always exists. + { + // Relative paths cannot be converted. + casePath = ""; + return 0; + } + + // Start with root component. + kwsys_stl::vector::size_type idx = 0; + casePath = path_components[idx++]; + 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 = "/"; + kwsys_stl::string test_str = casePath; + test_str += path_components[idx]; + + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile(test_str.c_str(), &findData); + if (INVALID_HANDLE_VALUE != hFind) + { + casePath += findData.cFileName; + ::FindClose(hFind); + } + else + { + casePath = ""; + return 0; + } + } + return (int)casePath.size(); +} +#endif + + +//---------------------------------------------------------------------------- +kwsys_stl::string SystemTools::GetActualCaseForPath(const char* p) +{ +#ifndef _WIN32 + return p; +#else + kwsys_stl::string casePath = p; + // make sure drive letter is always upper case + if(casePath.size() > 1 && casePath[1] == ':') + { + casePath[0] = toupper(casePath[0]); + } + + // Check to see if actual case has already been called + // for this path, and the result is stored in the LongPathMap + SystemToolsTranslationMap::iterator i = + SystemTools::LongPathMap->find(casePath); + if(i != SystemTools::LongPathMap->end()) + { + return i->second; + } + int len = GetCasePathName(p, casePath); + if(len == 0 || len > MAX_PATH+1) + { + return p; + } + (*SystemTools::LongPathMap)[p] = casePath; + return casePath; +#endif +} + +//---------------------------------------------------------------------------- +const char* SystemTools::SplitPathRootComponent(const char* p, + kwsys_stl::string* root) +{ + // Identify the root component. + const char* c = p; + 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 char* p, + kwsys_stl::vector& components, + bool expand_home_dir) +{ + const char* c = p; + components.clear(); + + // Identify the root component. + { + kwsys_stl::string root; + c = SystemTools::SplitPathRootComponent(c, &root); + + // Expand home directory references if requested. + if(expand_home_dir && !root.empty() && root[0] == '~') + { + kwsys_stl::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[homedir.size()-1] == '/' || + homedir[homedir.size()-1] == '\\')) + { + homedir = homedir.substr(0, homedir.size()-1); + } + SystemTools::SplitPath(homedir.c_str(), 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( + kwsys_stl::string(first,static_cast( + last-first))); + first = last+1; + } + } + + // Save the last component unless there were no components. + if(last != c) + { + components.push_back( + kwsys_stl::string(first,static_cast( + last-first))); + } +} + +//---------------------------------------------------------------------------- +kwsys_stl::string +SystemTools::JoinPath(const kwsys_stl::vector& components) +{ + return SystemTools::JoinPath(components.begin(), components.end()); +} + +//---------------------------------------------------------------------------- +kwsys_stl::string +SystemTools +::JoinPath(kwsys_stl::vector::const_iterator first, + kwsys_stl::vector::const_iterator last) +{ + // Construct result in a single string. + kwsys_stl::string result; + + // 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 char* c1, const char* c2) +{ +#if defined(_WIN32) || defined(__APPLE__) +# ifdef _MSC_VER + return _stricmp(c1, c2) == 0; +# elif defined(__APPLE__) || defined(__GNUC__) + return strcasecmp(c1, c2) == 0; +#else + return SystemTools::Strucmp(c1, c2) == 0; +# endif +#else + return strcmp(c1, c2) == 0; +#endif +} + +//---------------------------------------------------------------------------- +bool SystemTools::Split(const char* str, kwsys_stl::vector& lines, char separator) +{ + kwsys_stl::string data(str); + kwsys_stl::string::size_type lpos = 0; + while(lpos < data.length()) + { + kwsys_stl::string::size_type rpos = data.find_first_of(separator, lpos); + if(rpos == kwsys_stl::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 char* str, kwsys_stl::vector& lines) +{ + kwsys_stl::string data(str); + kwsys_stl::string::size_type lpos = 0; + while(lpos < data.length()) + { + kwsys_stl::string::size_type rpos = data.find_first_of("\n", lpos); + if(rpos == kwsys_stl::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. + */ +kwsys_stl::string SystemTools::GetFilenamePath(const kwsys_stl::string& filename) +{ + kwsys_stl::string fn = filename; + SystemTools::ConvertToUnixSlashes(fn); + + kwsys_stl::string::size_type slash_pos = fn.rfind("/"); + if(slash_pos != kwsys_stl::string::npos) + { + kwsys_stl::string ret = fn.substr(0, slash_pos); + if(ret.size() == 2 && ret[1] == ':') + { + return ret + '/'; + } + if(ret.size() == 0) + { + return "/"; + } + return ret; + } + else + { + return ""; + } +} + + +/** + * Return file name of a full filename (i.e. file name without path). + */ +kwsys_stl::string SystemTools::GetFilenameName(const kwsys_stl::string& filename) +{ +#if defined(_WIN32) + kwsys_stl::string::size_type slash_pos = filename.find_last_of("/\\"); +#else + kwsys_stl::string::size_type slash_pos = filename.find_last_of("/"); +#endif + if(slash_pos != kwsys_stl::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) + */ +kwsys_stl::string SystemTools::GetFilenameExtension(const kwsys_stl::string& filename) +{ + kwsys_stl::string name = SystemTools::GetFilenameName(filename); + kwsys_stl::string::size_type dot_pos = name.find("."); + if(dot_pos != kwsys_stl::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) + */ +kwsys_stl::string SystemTools::GetFilenameLastExtension(const kwsys_stl::string& filename) +{ + kwsys_stl::string name = SystemTools::GetFilenameName(filename); + kwsys_stl::string::size_type dot_pos = name.rfind("."); + if(dot_pos != kwsys_stl::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) + */ +kwsys_stl::string SystemTools::GetFilenameWithoutExtension(const kwsys_stl::string& filename) +{ + kwsys_stl::string name = SystemTools::GetFilenameName(filename); + kwsys_stl::string::size_type dot_pos = name.find("."); + if(dot_pos != kwsys_stl::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) + */ +kwsys_stl::string +SystemTools::GetFilenameWithoutLastExtension(const kwsys_stl::string& filename) +{ + kwsys_stl::string name = SystemTools::GetFilenameName(filename); + kwsys_stl::string::size_type dot_pos = name.rfind("."); + if(dot_pos != kwsys_stl::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; + 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; + } + + FILE *fp; + 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) + { + 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(read_length - text_count) / + static_cast(read_length)); + + if (current_percent_bin >= percent_bin) + { + return SystemTools::FileTypeBinary; + } + + return SystemTools::FileTypeText; +} + +bool SystemTools::LocateFileInDir(const char *filename, + const char *dir, + kwsys_stl::string& filename_found, + int try_filename_dirs) +{ + if (!filename || !dir) + { + return false; + } + + // Get the basename of 'filename' + + kwsys_stl::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 + + kwsys_stl::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.size() && dir) + { + size_t dir_len = strlen(dir); + int need_slash = + (dir_len && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\'); + + kwsys_stl::string temp = dir; + if (need_slash) + { + temp += "/"; + } + temp += filename_base; + + if (SystemTools::FileExists(temp.c_str())) + { + 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) + { + kwsys_stl::string filename_dir(filename); + kwsys_stl::string filename_dir_base; + kwsys_stl::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.size() || + filename_dir_base[filename_dir_base.size() - 1] == ':') +#else + if (!filename_dir_base.size()) +#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.size()); + } + } + + return res; +} + +bool SystemTools::FileIsFullPath(const char* in_name) +{ + kwsys_stl::string name = in_name; +#if defined(_WIN32) || defined(__CYGWIN__) + // On Windows, the name must be at least two characters long. + if(name.length() < 2) + { + return false; + } + if(name[1] == ':') + { + return true; + } + if(name[0] == '\\') + { + return true; + } +#else + // On UNIX, the name must be at least one character long. + if(name.length() < 1) + { + return false; + } +#endif +#if !defined(_WIN32) + if(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(name[0] == '/') + { + return true; + } + return false; +} + +bool SystemTools::GetShortPath(const char* path, kwsys_stl::string& shortPath) +{ +#if defined(WIN32) && !defined(__CYGWIN__) + const int size = int(strlen(path)) +1; // size of return + char *buffer = new char[size]; // create a buffer + char *tempPath = new char[size]; // create a buffer + int ret; + + // if the path passed in has quotes around it, first remove the quotes + if (path[0] == '"' && path[strlen(path)-1] == '"') + { + strcpy(tempPath,path+1); + tempPath[strlen(tempPath)-1] = '\0'; + } + else + { + strcpy(tempPath,path); + } + + buffer[0] = 0; + ret = GetShortPathName(tempPath, buffer, size); + + if(buffer[0] == 0 || ret > size) + { + delete [] buffer; + delete [] tempPath; + return false; + } + else + { + shortPath = buffer; + delete [] buffer; + delete [] tempPath; + return true; + } +#else + shortPath = path; + return true; +#endif +} + +void SystemTools::SplitProgramFromArgs(const char* path, + kwsys_stl::string& program, kwsys_stl::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 + kwsys_stl::vector e; + kwsys_stl::string findProg = SystemTools::FindProgram(path, e); + if(findProg.size()) + { + 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 + kwsys_stl::string dir = path; + kwsys_stl::string::size_type spacePos = dir.rfind(' '); + while(spacePos != kwsys_stl::string::npos) + { + kwsys_stl::string tryProg = dir.substr(0, spacePos); + // See if the file exists + if(SystemTools::FileExists(tryProg.c_str())) + { + program = tryProg; + // remove trailing spaces from program + kwsys_stl::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 the program in the path + findProg = SystemTools::FindProgram(tryProg.c_str(), e); + if(findProg.size()) + { + program = findProg; + // remove trailing spaces from program + kwsys_stl::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 = ""; +} + +kwsys_stl::string SystemTools::GetCurrentDateTime(const char* format) +{ + char buf[1024]; + time_t t; + time(&t); + strftime(buf, sizeof(buf), format, localtime(&t)); + return kwsys_stl::string(buf); +} + +kwsys_stl::string SystemTools::MakeCindentifier(const char* s) +{ + kwsys_stl::string str(s); + if (str.find_first_of("0123456789") == 0) + { + str = "_" + str; + } + + kwsys_stl::string permited_chars("_" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"); + kwsys_stl::string::size_type pos = 0; + while ((pos = str.find_first_not_of(permited_chars, pos)) != kwsys_stl::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(kwsys_ios::istream& is, + kwsys_stl::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 && + (is.clear(is.rdstate() & ~kwsys_ios::ios::failbit), + 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(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(length) > leftToRead) + { + buffer[leftToRead-1] = 0; + leftToRead = 0; + } + else + { + leftToRead -= static_cast(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(t); + } + } + if ( width < 9 ) + { + width = -1; + } +#endif + return width; +} + +bool SystemTools::GetPermissions(const char* file, mode_t& mode) +{ + if ( !file ) + { + return false; + } + + struct stat st; + if ( stat(file, &st) < 0 ) + { + return false; + } + mode = st.st_mode; + return true; +} + +bool SystemTools::SetPermissions(const char* file, mode_t mode) +{ + if ( !file ) + { + return false; + } + if ( !SystemTools::FileExists(file) ) + { + return false; + } + if ( chmod(file, mode) < 0 ) + { + return false; + } + + return true; +} + +kwsys_stl::string SystemTools::GetParentDirectory(const char* fileOrDir) +{ + return SystemTools::GetFilenamePath(fileOrDir); +} + +bool SystemTools::IsSubDirectory(const char* cSubdir, const char* cDir) +{ + if(!*cDir) + { + return false; + } + kwsys_stl::string subdir = cSubdir; + kwsys_stl::string dir = cDir; + SystemTools::ConvertToUnixSlashes(dir); + kwsys_stl::string path = subdir; + do + { + path = SystemTools::GetParentDirectory(path.c_str()); + if(SystemTools::ComparePath(dir.c_str(), path.c_str())) + { + return true; + } + } + while ( path.size() > dir.size() ); + 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 +} + +void SystemTools::ConvertWindowsCommandLineToUnixArguments( + const char *cmd_line, int *argc, char ***argv) +{ + if (!cmd_line || !argc || !argv) + { + return; + } + + // A space delimites an argument except when it is inside a quote + + (*argc) = 1; + + size_t cmd_line_len = strlen(cmd_line); + + size_t i; + for (i = 0; i < cmd_line_len; i++) + { + while (isspace(cmd_line[i]) && i < cmd_line_len) + { + i++; + } + if (i < cmd_line_len) + { + if (cmd_line[i] == '\"') + { + i++; + while (cmd_line[i] != '\"' && i < cmd_line_len) + { + i++; + } + (*argc)++; + } + else + { + while (!isspace(cmd_line[i]) && i < cmd_line_len) + { + i++; + } + (*argc)++; + } + } + } + + (*argv) = new char* [(*argc) + 1]; + (*argv)[(*argc)] = NULL; + + // Set the first arg to be the exec name + + (*argv)[0] = new char [1024]; +#ifdef _WIN32 + ::GetModuleFileName(0, (*argv)[0], 1024); +#else + (*argv)[0][0] = '\0'; +#endif + + // Allocate the others + + int j; + for (j = 1; j < (*argc); j++) + { + (*argv)[j] = new char [cmd_line_len + 10]; + } + + // Grab the args + + size_t pos; + int argc_idx = 1; + + for (i = 0; i < cmd_line_len; i++) + { + while (isspace(cmd_line[i]) && i < cmd_line_len) + { + i++; + } + if (i < cmd_line_len) + { + if (cmd_line[i] == '\"') + { + i++; + pos = i; + while (cmd_line[i] != '\"' && i < cmd_line_len) + { + i++; + } + memcpy((*argv)[argc_idx], &cmd_line[pos], i - pos); + (*argv)[argc_idx][i - pos] = '\0'; + argc_idx++; + } + else + { + pos = i; + while (!isspace(cmd_line[i]) && i < cmd_line_len) + { + i++; + } + memcpy((*argv)[argc_idx], &cmd_line[pos], i - pos); + (*argv)[argc_idx][i - pos] = '\0'; + argc_idx++; + } + } + } + } + +kwsys_stl::string SystemTools::GetOperatingSystemNameAndVersion() +{ + kwsys_stl::string res; + +#ifdef _WIN32 + char buffer[256]; + + OSVERSIONINFOEX osvi; + BOOL bOsVersionInfoEx; + + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + // If that fails, try using the OSVERSIONINFO structure. + + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *)&osvi); + if (!bOsVersionInfoEx) + { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (!GetVersionEx((OSVERSIONINFO *)&osvi)) + { + return 0; + } + } + + switch (osvi.dwPlatformId) + { + // Test for the Windows NT product family. + + case VER_PLATFORM_WIN32_NT: + + // Test for the specific product family. + + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) + { +#if (_MSC_VER >= 1300) + if (osvi.wProductType == VER_NT_WORKSTATION) + { + res += "Microsoft Windows Vista"; + } + else + { + res += "Microsoft Windows Server 2008 family"; + } +#else + res += "Microsoft Windows Vista or Windows Server 2008"; +#endif + } + + 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 (_MSC_VER >= 1300) + 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"; + } + } + } +#endif // Visual Studio 7 and up + } + + // Test for specific product on Windows NT 4.0 SP5 and earlier + + else + { + HKEY hKey; + #define BUFSIZE 80 + char szProductType[BUFSIZE]; + DWORD dwBufLen=BUFSIZE; + LONG lRet; + + lRet = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", + 0, KEY_QUERY_VALUE, &hKey); + if (lRet != ERROR_SUCCESS) + { + return 0; + } + + lRet = RegQueryValueEx(hKey, "ProductType", NULL, NULL, + (LPBYTE) szProductType, &dwBufLen); + + if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE)) + { + return 0; + } + + RegCloseKey(hKey); + + if (lstrcmpi("WINNT", szProductType) == 0) + { + res += " Workstation"; + } + if (lstrcmpi("LANMANNT", szProductType) == 0) + { + res += " Server"; + } + if (lstrcmpi("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 && + lstrcmpi(osvi.szCSDVersion, "Service Pack 6") == 0) + { + HKEY hKey; + LONG lRet; + + // Test for SP6 versus SP6a. + + lRet = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + "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 kwsys_stl::string& URL, + kwsys_stl::string& protocol, + kwsys_stl::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 kwsys_stl::string& URL, + kwsys_stl::string& protocol, + kwsys_stl::string& username, + kwsys_stl::string& password, + kwsys_stl::string& hostname, + kwsys_stl::string& dataport, + kwsys_stl::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. +unsigned int SystemToolsManagerCount; +SystemToolsTranslationMap *SystemTools::TranslationMap; +SystemToolsTranslationMap *SystemTools::LongPathMap; +#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; + SystemTools::LongPathMap = new SystemToolsTranslationMap; +#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. + kwsys_stl::string cwd_changed; + kwsys_stl::string pwd_changed; + + // Test progressively shorter logical-to-physical mappings. + kwsys_stl::string pwd_str = pwd; + kwsys_stl::string cwd_str = cwd; + kwsys_stl::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.c_str()); + cwd_str = SystemTools::GetFilenamePath(cwd_str.c_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.c_str(), + pwd_changed.c_str()); + } + } + } +#endif +} + +void SystemTools::ClassFinalize() +{ + delete SystemTools::TranslationMap; + delete SystemTools::LongPathMap; +#ifdef __CYGWIN__ + delete SystemTools::Cyg2Win32Map; +#endif +} + + +} // namespace KWSYS_NAMESPACE + +#if defined(_MSC_VER) && defined(_DEBUG) +# include +# include +# include +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")) + { + _CrtSetReportHook(SystemToolsDebugReport); + } +} + +} // namespace KWSYS_NAMESPACE +#else +namespace KWSYS_NAMESPACE +{ +void SystemTools::EnableMSVCDebugHook() {} +} // namespace KWSYS_NAMESPACE +#endif diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in new file mode 100644 index 000000000..5171125ce --- /dev/null +++ b/SystemTools.hxx.in @@ -0,0 +1,904 @@ +/*============================================================================ + 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@/ios/iosfwd> +#include <@KWSYS_NAMESPACE@/stl/string> +#include <@KWSYS_NAMESPACE@/stl/vector> +#include <@KWSYS_NAMESPACE@/stl/map> + +#include <@KWSYS_NAMESPACE@/Configure.h> +#include <@KWSYS_NAMESPACE@/String.hxx> + +#include + +// Required for va_list +#include +#if @KWSYS_NAMESPACE@_STL_HAVE_STD && !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 + +#if defined( _MSC_VER ) +typedef unsigned short mode_t; +#endif + +/* Define these macros temporarily to keep the code readable. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsys_stl @KWSYS_NAMESPACE@_stl +# define kwsys_ios @KWSYS_NAMESPACE@_ios +#endif + +namespace @KWSYS_NAMESPACE@ +{ + +class SystemToolsTranslationMap; +/** \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; + +/** \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 kwsys_stl::string MakeCindentifier(const char* s); + + /** + * Replace replace all occurences of the string in the source string. + */ + static void ReplaceString(kwsys_stl::string& source, + const char* replace, + const char* with); + + /** + * Return a capitalized string (i.e the first letter is uppercased, + * all other are lowercased). + */ + static kwsys_stl::string Capitalized(const kwsys_stl::string&); + + /** + * Return a 'capitalized words' string (i.e the first letter of each word + * is uppercased all other are left untouched though). + */ + static kwsys_stl::string CapitalizedWords(const kwsys_stl::string&); + + /** + * Return a 'uncapitalized words' string (i.e the first letter of each word + * is lowercased all other are left untouched though). + */ + static kwsys_stl::string UnCapitalizedWords(const kwsys_stl::string&); + + /** + * Return a lower case string + */ + static kwsys_stl::string LowerCase(const kwsys_stl::string&); + + /** + * Return a lower case string + */ + static kwsys_stl::string UpperCase(const kwsys_stl::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 StringEndsWith(const char* 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 kwsys_stl::string CropString(const kwsys_stl::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 kwsys_stl::vector SplitString(const char* 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 char* s, kwsys_stl::vector& l); + static bool Split(const char* s, kwsys_stl::vector& 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 kwsys_stl::string AddSpaceBetweenCapitalizedWords( + const kwsys_stl::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 kwsys_stl::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(kwsys_stl::string& path); + + /** + * For windows this calls ConvertToWindowsOutputPath and for unix + * it calls ConvertToUnixOutputPath + */ + static kwsys_stl::string ConvertToOutputPath(const char*); + + /** + * Convert the path to a string that can be used in a unix makefile. + * double slashes are removed, and spaces are escaped. + */ + static kwsys_stl::string ConvertToUnixOutputPath(const char*); + + /** + * 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 kwsys_stl::string ConvertToWindowsOutputPath(const char*); + + /** + * 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. + */ + static bool FileExists(const char* filename, bool isFile); + static bool FileExists(const char* filename); + + /** + * 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 char *filename); + + /** + Change the modification time or create a file + */ + static bool Touch(const char* 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 char* f1, const char* 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 kwsys_stl::string GetActualCaseForPath(const char* 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 kwsys_stl::string GetProgramPath(const char*); + static bool SplitProgramPath(const char* in_name, + kwsys_stl::string& dir, + kwsys_stl::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, + kwsys_stl::string& pathOut, + kwsys_stl::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 kwsys_stl::string CollapseFullPath(const char* in_relative); + static kwsys_stl::string CollapseFullPath(const char* in_relative, + const char* 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. + */ + static kwsys_stl::string GetRealPath(const char* path); + + /** + * 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 char* p, + kwsys_stl::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 char* p, + kwsys_stl::vector& 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 kwsys_stl::string JoinPath( + const kwsys_stl::vector& components); + static kwsys_stl::string JoinPath( + kwsys_stl::vector::const_iterator first, + kwsys_stl::vector::const_iterator last); + + /** + * Compare a path or components of a path. + */ + static bool ComparePath(const char* c1, const char* c2); + + + /** + * Return path of a full filename (no trailing slashes) + */ + static kwsys_stl::string GetFilenamePath(const kwsys_stl::string&); + + /** + * Return file name of a full filename (i.e. file name without path) + */ + static kwsys_stl::string GetFilenameName(const kwsys_stl::string&); + + /** + * Split a program from its arguments and handle spaces in the paths + */ + static void SplitProgramFromArgs( + const char* path, + kwsys_stl::string& program, kwsys_stl::string& args); + + /** + * Return longest file extension of a full filename (dot included) + */ + static kwsys_stl::string GetFilenameExtension(const kwsys_stl::string&); + + /** + * Return shortest file extension of a full filename (dot included) + */ + static kwsys_stl::string GetFilenameLastExtension( + const kwsys_stl::string& filename); + + /** + * Return file name without extension of a full filename + */ + static kwsys_stl::string GetFilenameWithoutExtension( + const kwsys_stl::string&); + + /** + * Return file name without its last (shortest) extension + */ + static kwsys_stl::string GetFilenameWithoutLastExtension( + const kwsys_stl::string&); + + /** + * Return whether the path represents a full path (not relative) + */ + static bool FileIsFullPath(const char*); + + /** + * For windows return the short path for the given path, + * Unix just a pass through + */ + static bool GetShortPath(const char* path, kwsys_stl::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(kwsys_ios::istream& istr, + kwsys_stl::string& line, + bool* has_newline=0, + long sizeLimit=-1); + + /** + * Get the parent directory of the directory or file + */ + static kwsys_stl::string GetParentDirectory(const char* fileOrDir); + + /** + * Check if the given file or directory is in subdirectory of dir + */ + static bool IsSubDirectory(const char* fileOrDir, const char* dir); + + /** ----------------------------------------------------------------- + * File Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** + * 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); + + /** + * Copy the source file to the destination file only + * if the two files differ. + */ + static bool CopyFileIfDifferent(const char* source, + const char* destination); + + /** + * Compare the contents of two files. Return true if different + */ + static bool FilesDiffer(const char* source, const char* destination); + + /** + * Return true if the two files are the same file + */ + static bool SameFile(const char* file1, const char* file2); + + /** + * Copy a file. + */ + static bool CopyFileAlways(const char* source, const char* 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 char* source, const char* 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 char* source, const char* destination, + bool always = true); + + /** + * Remove a file + */ + static bool RemoveFile(const char* source); + + /** + * Remove a directory + */ + static bool RemoveADirectory(const char* source); + + /** + * Get the maximum full file path length + */ + static size_t GetMaximumFilePathLength(); + + /** + * Find a file in the system PATH, with optional extra paths + */ + static kwsys_stl::string FindFile( + const char* name, + const kwsys_stl::vector& path = + kwsys_stl::vector(), + bool no_system_path = false); + + /** + * Find a directory in the system PATH, with optional extra paths + */ + static kwsys_stl::string FindDirectory( + const char* name, + const kwsys_stl::vector& path = + kwsys_stl::vector(), + bool no_system_path = false); + + /** + * Find an executable in the system PATH, with optional extra paths + */ + static kwsys_stl::string FindProgram( + const char* name, + const kwsys_stl::vector& path = + kwsys_stl::vector(), + bool no_system_path = false); + static kwsys_stl::string FindProgram( + const kwsys_stl::vector& names, + const kwsys_stl::vector& path = + kwsys_stl::vector(), + bool no_system_path = false); + + /** + * Find a library in the system PATH, with optional extra paths + */ + static kwsys_stl::string FindLibrary( + const char* name, + const kwsys_stl::vector& path); + + /** + * Return true if the file is a directory + */ + static bool FileIsDirectory(const char* name); + + /** + * Return true if the file is a symlink + */ + static bool FileIsSymlink(const char* 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 succeded. + */ + static bool CreateSymlink(const char* origName, const char* newName); + + /** + * Read the contents of a symbolic link. Returns whether reading + * succeded. + */ + static bool ReadSymlink(const char* newName, kwsys_stl::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, + kwsys_stl::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 kwsys_stl::string RelativePath(const char* local, const char* remote); + + /** + * Return file's modified time + */ + static long int ModifiedTime(const char* filename); + + /** + * Return file's creation time (Win32: works only for NTFS, not FAT) + */ + static long int CreationTime(const char* filename); + + /** + * Get and set permissions of the file. + */ + static bool GetPermissions(const char* file, mode_t& mode); + static bool SetPermissions(const char* file, mode_t mode); + + /** ----------------------------------------------------------------- + * Time Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** Get current time in seconds since Posix Epoch (Jan 1, 1970). */ + static double GetTime(); + + /** + * Get current date/time + */ + static kwsys_stl::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 }; + + /** + * Read a registry value + */ + static bool ReadRegistryValue(const char *key, kwsys_stl::string &value, + KeyWOW64 view = KeyWOW64_Default); + + /** + * Write a registry value + */ + static bool WriteRegistryValue(const char *key, const char *value, + KeyWOW64 view = KeyWOW64_Default); + + /** + * Delete a registry value + */ + static bool DeleteRegistryValue(const char *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(kwsys_stl::vector& path, + const char* env=0); + + /** + * Read an environment variable + */ + static const char* GetEnv(const char* key); + static bool GetEnv(const char* key, kwsys_stl::string& result); + + /** Put a string into the environment + of the form var=value */ + static bool PutEnv(const char* env); + + /** Remove a string from the environment. + Input is of the form "var" or "var=value" (value is ignored). */ + static bool UnPutEnv(const char* env); + + /** + * Get current working directory CWD + */ + static kwsys_stl::string GetCurrentWorkingDirectory(bool collapse =true); + + /** + * Change directory the the directory specified + */ + static int ChangeDirectory(const char* dir); + + /** + * Get the result of strerror(errno) + */ + static kwsys_stl::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 char * dir, const char * refdir); + + /** + * If dir is different after CollapseFullPath is called, + * Then insert it into the path translation table + */ + static void AddKeepPath(const char* dir); + + /** + * Update path by going through the Path Translation table; + */ + static void CheckTranslationPath(kwsys_stl::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 kwsys_stl::string GetOperatingSystemNameAndVersion(); + + /** + * Convert windows-style arguments given as a command-line string + * into more traditional argc/argv arguments. + * Note that argv[0] will be assigned the executable name using + * the GetModuleFileName() function. + */ + static void ConvertWindowsCommandLineToUnixArguments( + const char *cmd_line, int *argc, char ***argv); + + /** ----------------------------------------------------------------- + * 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 kwsys_stl::string& URL, + kwsys_stl::string& protocol, + kwsys_stl::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 kwsys_stl::string& URL, + kwsys_stl::string& protocol, + kwsys_stl::string& username, + kwsys_stl::string& password, + kwsys_stl::string& hostname, + kwsys_stl::string& dataport, + kwsys_stl::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; + } + + /** + * Find a filename (file or directory) in the system PATH, with + * optional extra paths. + */ + static kwsys_stl::string FindName( + const char* name, + const kwsys_stl::vector& path = + kwsys_stl::vector(), + 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; + static SystemToolsTranslationMap *LongPathMap; +#ifdef __CYGWIN__ + static SystemToolsTranslationMap *Cyg2Win32Map; +#endif + friend class SystemToolsManager; +}; + +} // namespace @KWSYS_NAMESPACE@ + +/* Undefine temporary macros. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsys_stl +# undef kwsys_ios +#endif + +#endif diff --git a/Terminal.c b/Terminal.c new file mode 100644 index 000000000..25832c2b1 --- /dev/null +++ b/Terminal.c @@ -0,0 +1,432 @@ +/*============================================================================ + 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 /* getenv */ +#include /* strcmp */ +#include /* va_list */ + +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) +# include /* SetConsoleTextAttribute */ +# include /* _get_osfhandle */ +#endif + +#if defined(KWSYS_TERMINAL_ISATTY_WORKS) +# include /* isatty */ +#else +# include /* 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 definately not interactive. */ +#if !defined(KWSYS_TERMINAL_ISATTY_WORKS) +static int kwsysTerminalStreamIsNotInteractive(FILE* stream) +{ + /* The given stream is definately 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", + "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", + 0 +}; + +/*--------------------------------------------------------------------------*/ +/* Detect whether a stream is displayed in a VT100-compatible terminal. */ +static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, + int default_tty) +{ + /* 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 definately 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/Terminal.h.in b/Terminal.h.in new file mode 100644 index 000000000..108cba017 --- /dev/null +++ b/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 /* 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/auto_ptr.hxx.in b/auto_ptr.hxx.in new file mode 100644 index 000000000..857b1db3c --- /dev/null +++ b/auto_ptr.hxx.in @@ -0,0 +1,201 @@ +/*============================================================================ + 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@_auto_ptr_hxx +#define @KWSYS_NAMESPACE@_auto_ptr_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +// The HP compiler and VS6 cannot handle the conversions necessary to use +// auto_ptr_ref to pass an auto_ptr returned from one function +// directly to another function as in use_auto_ptr(get_auto_ptr()). +// We instead use const_cast to achieve the syntax on those platforms. +// We do not use const_cast on other platforms to maintain the C++ +// standard design and guarantee that if an auto_ptr is bound +// to a reference-to-const then ownership will be maintained. +#if defined(__HP_aCC) || (defined(_MSC_VER) && _MSC_VER <= 1200) +# define @KWSYS_NAMESPACE@_AUTO_PTR_REF 0 +# define @KWSYS_NAMESPACE@_AUTO_PTR_CONST const +# define @KWSYS_NAMESPACE@_AUTO_PTR_CAST(a) cast(a) +#else +# define @KWSYS_NAMESPACE@_AUTO_PTR_REF 1 +# define @KWSYS_NAMESPACE@_AUTO_PTR_CONST +# define @KWSYS_NAMESPACE@_AUTO_PTR_CAST(a) a +#endif + +namespace @KWSYS_NAMESPACE@ +{ + +template class auto_ptr; + +#if @KWSYS_NAMESPACE@_AUTO_PTR_REF +namespace detail +{ +// The auto_ptr_ref template is supposed to be a private member of +// auto_ptr but Borland 5.8 cannot handle it. Instead put it in +// a private namespace. +template struct auto_ptr_ref +{ + Y* p_; + + // The extra constructor argument prevents implicit conversion to + // auto_ptr_ref from auto_ptr through the constructor. Normally + // this should be done with the explicit keyword but Borland 5.x + // generates code in the conversion operator to call itself + // infinately. + auto_ptr_ref(Y* p, int): p_(p) {} +}; +} +#endif + +/** C++98 Standard Section 20.4.5 - Template class auto_ptr. */ +template +class auto_ptr +{ +#if !@KWSYS_NAMESPACE@_AUTO_PTR_REF + template + static inline auto_ptr& cast(auto_ptr const& a) + { return const_cast&>(a); } +#endif + + /** The pointer to the object held. */ + X* x_; + +public: + /** The type of object held by the auto_ptr. */ + typedef X element_type; + + /** Construct from an auto_ptr holding a compatible object. This + transfers ownership to the newly constructed auto_ptr. */ + template + auto_ptr(auto_ptr @KWSYS_NAMESPACE@_AUTO_PTR_CONST& a) throw(): + x_(@KWSYS_NAMESPACE@_AUTO_PTR_CAST(a).release()) + { + } + + /** Assign from an auto_ptr holding a compatible object. This + transfers ownership to the left-hand-side of the assignment. */ + template + auto_ptr& operator=(auto_ptr @KWSYS_NAMESPACE@_AUTO_PTR_CONST& a) throw() + { + this->reset(@KWSYS_NAMESPACE@_AUTO_PTR_CAST(a).release()); + return *this; + } + + /** + * Explicitly construct from a raw pointer. This is typically + * called with the result of operator new. For example: + * + * auto_ptr ptr(new X()); + */ + explicit auto_ptr(X* p=0) throw(): x_(p) + { + } + + /** Construct from another auto_ptr holding an object of the same + type. This transfers ownership to the newly constructed + auto_ptr. */ + auto_ptr(auto_ptr @KWSYS_NAMESPACE@_AUTO_PTR_CONST& a) throw(): + x_(@KWSYS_NAMESPACE@_AUTO_PTR_CAST(a).release()) + { + } + + /** Assign from another auto_ptr holding an object of the same type. + This transfers ownership to the newly constructed auto_ptr. */ + auto_ptr& operator=(auto_ptr @KWSYS_NAMESPACE@_AUTO_PTR_CONST& a) throw() + { + this->reset(@KWSYS_NAMESPACE@_AUTO_PTR_CAST(a).release()); + return *this; + } + + /** Destruct and delete the object held. */ + ~auto_ptr() throw() + { + // Assume object destructor is nothrow. + delete this->x_; + } + + /** Dereference and return a reference to the object held. */ + X& operator*() const throw() + { + return *this->x_; + } + + /** Return a pointer to the object held. */ + X* operator->() const throw() + { + return this->x_; + } + + /** Return a pointer to the object held. */ + X* get() const throw() + { + return this->x_; + } + + /** Return a pointer to the object held and reset to hold no object. + This transfers ownership to the caller. */ + X* release() throw() + { + X* x = this->x_; + this->x_ = 0; + return x; + } + + /** Assume ownership of the given object. The object previously + held is deleted. */ + void reset(X* p=0) throw() + { + if(this->x_ != p) + { + // Assume object destructor is nothrow. + delete this->x_; + this->x_ = p; + } + } + + /** Convert to an auto_ptr holding an object of a compatible type. + This transfers ownership to the returned auto_ptr. */ + template operator auto_ptr() throw() + { + return auto_ptr(this->release()); + } + +#if @KWSYS_NAMESPACE@_AUTO_PTR_REF + /** Construct from an auto_ptr_ref. This is used when the + constructor argument is a call to a function returning an + auto_ptr. */ + auto_ptr(detail::auto_ptr_ref r) throw(): x_(r.p_) + { + } + + /** Assign from an auto_ptr_ref. This is used when a function + returning an auto_ptr is passed on the right-hand-side of an + assignment. */ + auto_ptr& operator=(detail::auto_ptr_ref r) throw() + { + this->reset(r.p_); + return *this; + } + + /** Convert to an auto_ptr_ref. This is used when a function + returning an auto_ptr is the argument to the constructor of + another auto_ptr. */ + template operator detail::auto_ptr_ref() throw() + { + return detail::auto_ptr_ref(this->release(), 1); + } +#endif +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/hash_fun.hxx.in b/hash_fun.hxx.in new file mode 100644 index 000000000..6f787ddc5 --- /dev/null +++ b/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 <@KWSYS_NAMESPACE@/cstddef> // size_t +#include <@KWSYS_NAMESPACE@/stl/string> // string + +namespace @KWSYS_NAMESPACE@ +{ + +template 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); +} + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(const char* __s) const { return _stl_hash_string(__s); } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(const char* __s) const { return _stl_hash_string(__s); } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION + struct hash<@KWSYS_NAMESPACE@_stl::string> { + size_t operator()(const @KWSYS_NAMESPACE@_stl::string & __s) const { return _stl_hash_string(__s.c_str()); } +}; + +#if !defined(__BORLANDC__) +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION + struct hash { + size_t operator()(const @KWSYS_NAMESPACE@_stl::string & __s) const { return _stl_hash_string(__s.c_str()); } +}; +#endif + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(char __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(unsigned char __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(unsigned char __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(short __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(unsigned short __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(int __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(unsigned int __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(long __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(unsigned long __x) const { return __x; } +}; + +// use long long or __int64 +#if @KWSYS_USE_LONG_LONG@ +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(long long __x) const { return __x; } +}; + +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(unsigned long long __x) const { return __x; } +}; +#elif @KWSYS_USE___INT64@ +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash<__int64> { + size_t operator()(__int64 __x) const { return __x; } +}; +@KWSYS_NAMESPACE@_CXX_DEFINE_SPECIALIZATION +struct hash { + size_t operator()(unsigned __int64 __x) const { return __x; } +}; +#endif // use long long or __int64 + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/hash_map.hxx.in b/hash_map.hxx.in new file mode 100644 index 000000000..6d4379d8e --- /dev/null +++ b/hash_map.hxx.in @@ -0,0 +1,461 @@ +/*============================================================================ + 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 <@KWSYS_NAMESPACE@/stl/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 +struct hash_select1st: + public @KWSYS_NAMESPACE@_stl::unary_function<@KWSYS_NAMESPACE@_stl::pair, T1> +{ + const T1& operator()(const @KWSYS_NAMESPACE@_stl::pair& __x) const + { return __x.first; } +}; + +// Forward declaration of equality operator; needed for friend declaration. + +template , + class _EqualKey = @KWSYS_NAMESPACE@_stl::equal_to<_Key>, + class _Alloc = @KWSYS_NAMESPACE@_HASH_DEFAULT_ALLOCATOR(char) > +class hash_map; + +template +bool operator==(const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&, + const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&); + +template +class hash_map +{ +private: + typedef hashtable<@KWSYS_NAMESPACE@_stl::pair,_Key,_HashFcn, + hash_select1st,_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) {} + +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + hash_map(_InputIterator __f, _InputIterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + template + hash_map(_InputIterator __f, _InputIterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + template + 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 + 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); } + +#else + hash_map(const value_type* __f, const value_type* __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_map(const value_type* __f, const value_type* __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_map(const value_type* __f, const value_type* __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_map(const value_type* __f, const value_type* __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); } + + hash_map(const_iterator __f, const_iterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_map(const_iterator __f, const_iterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_map(const_iterator __f, const_iterator __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_map(const_iterator __f, const_iterator __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); } +#endif + +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==@KWSYS_NAMESPACE@_CXX_NULL_TEMPLATE_ARGS(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: + @KWSYS_NAMESPACE@_stl::pair insert(const value_type& __obj) + { return _M_ht.insert_unique(__obj); } +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + void insert(_InputIterator __f, _InputIterator __l) + { _M_ht.insert_unique(__f,__l); } +#else + void insert(const value_type* __f, const value_type* __l) { + _M_ht.insert_unique(__f,__l); + } + void insert(const_iterator __f, const_iterator __l) + { _M_ht.insert_unique(__f, __l); } +#endif + @KWSYS_NAMESPACE@_stl::pair 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); } + + @KWSYS_NAMESPACE@_stl::pair equal_range(const key_type& __key) + { return _M_ht.equal_range(__key); } + @KWSYS_NAMESPACE@_stl::pair + 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 +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 +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 +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 _EqualKey = @KWSYS_NAMESPACE@_stl::equal_to<_Key>, + class _Alloc = @KWSYS_NAMESPACE@_HASH_DEFAULT_ALLOCATOR(char) > +class hash_multimap; + +template +bool +operator==(const hash_multimap<_Key,_Tp,_HF,_EqKey,_Alloc>& __hm1, + const hash_multimap<_Key,_Tp,_HF,_EqKey,_Alloc>& __hm2); + +template +class hash_multimap +{ +private: + typedef hashtable<@KWSYS_NAMESPACE@_stl::pair, _Key, _HashFcn, + hash_select1st, _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) {} + +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + hash_multimap(_InputIterator __f, _InputIterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + template + hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + template + 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 + 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); } + +#else + hash_multimap(const value_type* __f, const value_type* __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multimap(const value_type* __f, const value_type* __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multimap(const value_type* __f, const value_type* __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multimap(const value_type* __f, const value_type* __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); } + + hash_multimap(const_iterator __f, const_iterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multimap(const_iterator __f, const_iterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multimap(const_iterator __f, const_iterator __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multimap(const_iterator __f, const_iterator __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); } +#endif + +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==@KWSYS_NAMESPACE@_CXX_NULL_TEMPLATE_ARGS(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); } +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + void insert(_InputIterator __f, _InputIterator __l) + { _M_ht.insert_equal(__f,__l); } +#else + void insert(const value_type* __f, const value_type* __l) { + _M_ht.insert_equal(__f,__l); + } + void insert(const_iterator __f, const_iterator __l) + { _M_ht.insert_equal(__f, __l); } +#endif + 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); } + + @KWSYS_NAMESPACE@_stl::pair equal_range(const key_type& __key) + { return _M_ht.equal_range(__key); } + @KWSYS_NAMESPACE@_stl::pair + 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 +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 +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 +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/hash_set.hxx.in b/hash_set.hxx.in new file mode 100644 index 000000000..5ee01a594 --- /dev/null +++ b/hash_set.hxx.in @@ -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. +============================================================================*/ +/* + * 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 <@KWSYS_NAMESPACE@/stl/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 +struct _Identity : public @KWSYS_NAMESPACE@_stl::unary_function<_Tp,_Tp> +{ + const _Tp& operator()(const _Tp& __x) const { return __x; } +}; + +// Forward declaration of equality operator; needed for friend declaration. + +template , + class _EqualKey = @KWSYS_NAMESPACE@_stl::equal_to<_Value>, + class _Alloc = @KWSYS_NAMESPACE@_HASH_DEFAULT_ALLOCATOR(char) > +class hash_set; + +template +bool +operator==(const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs1, + const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs2); + +template +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) {} + +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + hash_set(_InputIterator __f, _InputIterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + template + hash_set(_InputIterator __f, _InputIterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + template + 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 + 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); } +#else + + hash_set(const value_type* __f, const value_type* __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_set(const value_type* __f, const value_type* __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_set(const value_type* __f, const value_type* __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_set(const value_type* __f, const value_type* __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); } + + hash_set(const_iterator __f, const_iterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_set(const_iterator __f, const_iterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_set(const_iterator __f, const_iterator __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { _M_ht.insert_unique(__f, __l); } + hash_set(const_iterator __f, const_iterator __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); } +#endif + +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==@KWSYS_NAMESPACE@_CXX_NULL_TEMPLATE_ARGS(const hash_set&, + const hash_set&); + + iterator begin() const { return _M_ht.begin(); } + iterator end() const { return _M_ht.end(); } + +public: + @KWSYS_NAMESPACE@_stl::pair insert(const value_type& __obj) + { + typedef typename _Ht::iterator _Ht_iterator; + @KWSYS_NAMESPACE@_stl::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique(__obj); + return @KWSYS_NAMESPACE@_stl::pair(__p.first, __p.second); + } +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + void insert(_InputIterator __f, _InputIterator __l) + { _M_ht.insert_unique(__f,__l); } +#else + void insert(const value_type* __f, const value_type* __l) { + _M_ht.insert_unique(__f,__l); + } + void insert(const_iterator __f, const_iterator __l) + {_M_ht.insert_unique(__f, __l); } +#endif + @KWSYS_NAMESPACE@_stl::pair insert_noresize(const value_type& __obj) + { + typedef typename _Ht::iterator _Ht_iterator; + @KWSYS_NAMESPACE@_stl::pair<_Ht_iterator, bool> __p = + _M_ht.insert_unique_noresize(__obj); + return @KWSYS_NAMESPACE@_stl::pair(__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); } + + @KWSYS_NAMESPACE@_stl::pair 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 +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 +inline bool +operator!=(const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs1, + const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs2) { + return !(__hs1 == __hs2); +} + +template +inline void +swap(hash_set<_Val,_HashFcn,_EqualKey,_Alloc>& __hs1, + hash_set<_Val,_HashFcn,_EqualKey,_Alloc>& __hs2) +{ + __hs1.swap(__hs2); +} + +template , + class _EqualKey = @KWSYS_NAMESPACE@_stl::equal_to<_Value>, + class _Alloc = @KWSYS_NAMESPACE@_HASH_DEFAULT_ALLOCATOR(char) > +class hash_multiset; + +template +bool +operator==(const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs1, + const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs2); + + +template +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) {} + +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + hash_multiset(_InputIterator __f, _InputIterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + template + hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + template + 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 + 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); } +#else + + hash_multiset(const value_type* __f, const value_type* __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multiset(const value_type* __f, const value_type* __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multiset(const value_type* __f, const value_type* __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multiset(const value_type* __f, const value_type* __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); } + + hash_multiset(const_iterator __f, const_iterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multiset(const_iterator __f, const_iterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multiset(const_iterator __f, const_iterator __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { _M_ht.insert_equal(__f, __l); } + hash_multiset(const_iterator __f, const_iterator __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); } +#endif + +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==@KWSYS_NAMESPACE@_CXX_NULL_TEMPLATE_ARGS(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); } +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + void insert(_InputIterator __f, _InputIterator __l) + { _M_ht.insert_equal(__f,__l); } +#else + void insert(const value_type* __f, const value_type* __l) { + _M_ht.insert_equal(__f,__l); + } + void insert(const_iterator __f, const_iterator __l) + { _M_ht.insert_equal(__f, __l); } +#endif + 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); } + + @KWSYS_NAMESPACE@_stl::pair 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 +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 +inline bool +operator!=(const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs1, + const hash_multiset<_Val,_HashFcn,_EqualKey,_Alloc>& __hs2) { + return !(__hs1 == __hs2); +} + +template +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/hashtable.hxx.in b/hashtable.hxx.in new file mode 100644 index 000000000..db52fc846 --- /dev/null +++ b/hashtable.hxx.in @@ -0,0 +1,1275 @@ +/*============================================================================ + 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 <@KWSYS_NAMESPACE@/cstddef> // size_t +#include <@KWSYS_NAMESPACE@/stl/algorithm> // lower_bound +#include <@KWSYS_NAMESPACE@/stl/functional> // unary_function +#include <@KWSYS_NAMESPACE@/stl/iterator> // iterator_traits +#include <@KWSYS_NAMESPACE@/stl/memory> // allocator +#include <@KWSYS_NAMESPACE@/stl/utility> // pair +#include <@KWSYS_NAMESPACE@/stl/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 + +#if @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_TEMPLATE +# define @KWSYS_NAMESPACE@_HASH_DEFAULT_ALLOCATOR(T) @KWSYS_NAMESPACE@_stl::allocator< T > +#elif @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_NONTEMPLATE +# define @KWSYS_NAMESPACE@_HASH_DEFAULT_ALLOCATOR(T) @KWSYS_NAMESPACE@_stl::allocator +#else +# define @KWSYS_NAMESPACE@_HASH_DEFAULT_ALLOCATOR(T) @KWSYS_NAMESPACE@_stl::alloc +#endif + +#if @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_OBJECTS +# define @KWSYS_NAMESPACE@_HASH_BUCKETS_INIT(__a) _M_buckets(__a) +# define @KWSYS_NAMESPACE@_HASH_BUCKETS_GET_ALLOCATOR(__b) , __b.get_allocator() +#else +# define @KWSYS_NAMESPACE@_HASH_BUCKETS_INIT(__a) _M_buckets() +# define @KWSYS_NAMESPACE@_HASH_BUCKETS_GET_ALLOCATOR(__b) +#endif + +namespace @KWSYS_NAMESPACE@ +{ + +//---------------------------------------------------------------------------- +// Define an allocator adaptor for platforms that do not provide an +// allocator with the rebind member. +#if !@KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_REBIND + +// Utility functions to convert item counts. +inline size_t hash_sizeof(void*) { return sizeof(char); } +inline size_t hash_sizeof(const void*) { return sizeof(char); } +template inline size_t hash_sizeof(TPtr p) +{ + static_cast(p); + return sizeof(*p); +} +template +inline TSize hash_allocator_n(POut out, PIn in, TSize n) +{ + return n*(hash_sizeof(out)/hash_sizeof(in) + + (hash_sizeof(out)%hash_sizeof(in)>0)); +} + +// Define an allocation method to use the native allocator with +// the proper signature. The following signatures of the allocate +// method are used on various STL implementations: +// pointer allocate(size_type, const void* hint) +// pointer allocate(size_type) +// static pointer allocate(size_type, const void* hint) +// static pointer allocate(size_type) +// Where pointer might be a real type or void*. +// This set of overloads decodes the signature for a particular STL. +// The extra three int/long arguments will favor certain signatures +// over others in the case that multiple are present to avoid +// ambiguity errors. +template +inline void hash_allocate(TAlloc* a, PIn (TAlloc::*allocate)(TSize, THint), + TSize n_out, const void* hint, POut& out, + int, int, int) +{ + TSize n_in = hash_allocator_n(POut(), PIn(), n_out); + void* vout = (a->*allocate)(n_in, const_cast(hint)); + out = static_cast(vout); +} + +template +inline void hash_allocate(TAlloc* a, PIn (TAlloc::*allocate)(TSize), + TSize n_out, const void*, POut& out, + int, int, long) +{ + TSize n_in = hash_allocator_n(POut(), PIn(), n_out); + void* vout = (a->*allocate)(n_in); + out = static_cast(vout); +} + +template +inline void hash_allocate(void*, PIn (*allocate)(TSize, THint), + TSize n_out, const void* hint, POut& out, + int, long, long) +{ + TSize n_in = hash_allocator_n(POut(), PIn(), n_out); + void* vout = allocate(n_in, const_cast(hint)); + out = static_cast(vout); +} + +template +inline void hash_allocate(void*, PIn (*allocate)(TSize), + TSize n_out, const void*, POut& out, + long, long, long) +{ + TSize n_in = hash_allocator_n(POut(), PIn(), n_out); + void* vout = allocate(n_in); + out = static_cast(vout); +} + +// Define a deallocation method to use the native allocator with +// the proper signature. The following signatures of the deallocate +// method are used on various STL implementations: +// void deallocate(pointer, size_type) +// void deallocate(pointer) +// static void deallocate(pointer, size_type) +// static void deallocate(pointer) +// Where pointer might be a real type or void*. +// This set of overloads decodes the signature for a particular STL. +// The extra three int/long arguments will favor certain signatures +// over others in the case that multiple are present to avoid +// ambiguity errors. +template +inline void hash_deallocate(TAlloc* a, void (TAlloc::*deallocate)(PIn, TSize), + PInReal, POut p, TSize n_out, int, int, int) +{ + TSize n_in = hash_allocator_n(POut(), PInReal(), n_out); + void* vout = p; + (a->*deallocate)(static_cast(vout), n_in); +} + +template +inline void hash_deallocate(TAlloc* a, void (TAlloc::*deallocate)(PIn), + PInReal, POut p, TSize, int, int, long) +{ + void* vout = p; + (a->*deallocate)(static_cast(vout)); +} + +template +inline void hash_deallocate(void*, void (*deallocate)(PIn, TSize), + PInReal, POut p, TSize n_out, int, long, long) +{ + TSize n_in = hash_allocator_n(POut(), PInReal(), n_out); + void* vout = p; + deallocate(static_cast(vout), n_in); +} + +template +inline void hash_deallocate(void*, void (*deallocate)(PIn), + PInReal, POut p, TSize, long, long, long) +{ + void* vout = p; + deallocate(static_cast(vout)); +} + +// Use the same four overloads as hash_allocate to decode the type +// really used for allocation. This is passed as PInReal to the +// deallocate functions so that hash_allocator_n has the proper size. +template +inline PIn hash_allocate_type(PIn (TAlloc::*)(TSize, THint), + int, int, int) { return 0; } +template +inline PIn hash_allocate_type(PIn (TAlloc::*)(TSize), + int, int, long) { return 0; } +template +inline PIn hash_allocate_type(PIn (*)(TSize, THint), + int, long, long) { return 0; } +template +inline PIn hash_allocate_type(PIn (*)(TSize), + long, long, long) { return 0; } + +// Define the comparison operators in terms of a base type to avoid +// needing templated versions. +class hash_allocator_base {}; +inline bool operator==(const hash_allocator_base&, + const hash_allocator_base&) throw() { return true; } +inline bool operator!=(const hash_allocator_base&, + const hash_allocator_base&) throw() { return false; } + +// Define the allocator template. +template +class hash_allocator: public hash_allocator_base +{ +private: + // Store the real allocator privately. + typedef Alloc alloc_type; + alloc_type alloc_; + +public: + // Standard allocator interface. + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + hash_allocator() throw(): alloc_() {} + hash_allocator(const hash_allocator_base&) throw() : alloc_() {} + hash_allocator(const hash_allocator& a) throw() : alloc_(a.alloc_) {} + hash_allocator(const alloc_type& a) throw() : alloc_(a) {} + ~hash_allocator() throw() {} +# if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES + template + struct rebind { typedef hash_allocator other; }; +# endif + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + typedef void* void_pointer; + typedef const void* const_void_pointer; + pointer allocate(size_type n=1, const_void_pointer hint = 0) + { + if(n) + { + pointer p; + hash_allocate(&alloc_, &alloc_type::allocate, n, hint, p, 1, 1, 1); + return p; + } + else + { + return 0; + } + } + void deallocate(pointer p, size_type n=1) + { + if(n) + { + hash_deallocate(&alloc_, &alloc_type::deallocate, + hash_allocate_type(&alloc_type::allocate, 1, 1, 1), + p, n, 1, 1, 1); + } + } +#if @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_MAX_SIZE_ARGUMENT + size_type max_size(size_type s) const throw() + { + return alloc_.max_size(s); + } +#else + size_type max_size() const throw() + { + size_type n = alloc_.max_size() / sizeof(value_type); + return n>0? n:1; + } +#endif + void construct(pointer p, const value_type& val) { new (p) value_type(val); } + void destroy(pointer p) { (void)p; p->~value_type(); } +}; +#endif + +template +struct _Hashtable_node +{ + _Hashtable_node* _M_next; + _Val _M_val; +}; + +template +class hashtable; + +template +struct _Hashtable_iterator; + +template +struct _Hashtable_const_iterator; + +template +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 @KWSYS_NAMESPACE@_stl::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 +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 @KWSYS_NAMESPACE@_stl::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 +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]; } + +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 = @KWSYS_NAMESPACE@_stl::lower_bound(__first, __last, __n); + return pos == __last ? *(__last - 1) : *pos; +} + +// Forward declaration of operator==. + +template +class hashtable; + +template +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 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; + +#if @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_REBIND +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 @KWSYS_NAMESPACE@_stl::vector<_Node*,_M_node_ptr_allocator_type> _M_buckets_type; +#else +public: + typedef hash_allocator<_Val, _Alloc> allocator_type; + allocator_type get_allocator() const { return allocator_type(); } +private: + typedef hash_allocator<_Node, _Alloc> _M_node_allocator_type; +# if @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_OBJECTS + typedef hash_allocator<_Node*, _Alloc> _M_node_ptr_allocator_type; +# else + typedef _Alloc _M_node_ptr_allocator_type; +# endif + typedef @KWSYS_NAMESPACE@_stl::vector<_Node*,_M_node_ptr_allocator_type> _M_buckets_type; +#endif + +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), + @KWSYS_NAMESPACE@_HASH_BUCKETS_INIT(__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()), + @KWSYS_NAMESPACE@_HASH_BUCKETS_INIT(__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), + @KWSYS_NAMESPACE@_HASH_BUCKETS_INIT(__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) + { + @KWSYS_NAMESPACE@_stl::swap(_M_hash, __ht._M_hash); + @KWSYS_NAMESPACE@_stl::swap(_M_equals, __ht._M_equals); + @KWSYS_NAMESPACE@_stl::swap(_M_get_key, __ht._M_get_key); + _M_buckets.swap(__ht._M_buckets); + @KWSYS_NAMESPACE@_stl::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==@KWSYS_NAMESPACE@_CXX_NULL_TEMPLATE_ARGS(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; + } + + @KWSYS_NAMESPACE@_stl::pair 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); + } + + @KWSYS_NAMESPACE@_stl::pair insert_unique_noresize(const value_type& __obj); + iterator insert_equal_noresize(const value_type& __obj); + +#if @KWSYS_NAMESPACE@_STL_HAS_ITERATOR_TRAITS +# define @KWSYS_NAMESPACE@_HASH_ITERATOR_CATEGORY(T,I) \ + typename @KWSYS_NAMESPACE@_stl::iterator_traits< T >::iterator_category() +#elif @KWSYS_NAMESPACE@_STL_HAS_ITERATOR_CATEGORY +# define @KWSYS_NAMESPACE@_HASH_ITERATOR_CATEGORY(T,I) \ + @KWSYS_NAMESPACE@_stl::iterator_category( I ) +#elif @KWSYS_NAMESPACE@_STL_HAS___ITERATOR_CATEGORY +# define @KWSYS_NAMESPACE@_HASH_ITERATOR_CATEGORY(T,I) \ + @KWSYS_NAMESPACE@_stl::__iterator_category( I ) +#endif + +#if @KWSYS_NAMESPACE@_CXX_HAS_MEMBER_TEMPLATES && defined(@KWSYS_NAMESPACE@_HASH_ITERATOR_CATEGORY) + template + void insert_unique(_InputIterator __f, _InputIterator __l) + { + insert_unique(__f, __l, + @KWSYS_NAMESPACE@_HASH_ITERATOR_CATEGORY(_InputIterator, __f)); + } + + template + void insert_equal(_InputIterator __f, _InputIterator __l) + { + insert_equal(__f, __l, + @KWSYS_NAMESPACE@_HASH_ITERATOR_CATEGORY(_InputIterator, __f)); + } + + template + void insert_unique(_InputIterator __f, _InputIterator __l, + @KWSYS_NAMESPACE@_stl::input_iterator_tag) + { + for ( ; __f != __l; ++__f) + insert_unique(*__f); + } + + template + void insert_equal(_InputIterator __f, _InputIterator __l, + @KWSYS_NAMESPACE@_stl::input_iterator_tag) + { + for ( ; __f != __l; ++__f) + insert_equal(*__f); + } + + template + void insert_unique(_ForwardIterator __f, _ForwardIterator __l, + @KWSYS_NAMESPACE@_stl::forward_iterator_tag) + { + size_type __n = 0; + @KWSYS_NAMESPACE@_stl::distance(__f, __l, __n); + resize(_M_num_elements + __n); + for ( ; __n > 0; --__n, ++__f) + insert_unique_noresize(*__f); + } + + template + void insert_equal(_ForwardIterator __f, _ForwardIterator __l, + @KWSYS_NAMESPACE@_stl::forward_iterator_tag) + { + size_type __n = 0; + @KWSYS_NAMESPACE@_stl::distance(__f, __l, __n); + resize(_M_num_elements + __n); + for ( ; __n > 0; --__n, ++__f) + insert_equal_noresize(*__f); + } + +#else + void insert_unique(const value_type* __f, const value_type* __l) + { + size_type __n = __l - __f; + resize(_M_num_elements + __n); + for ( ; __n > 0; --__n, ++__f) + insert_unique_noresize(*__f); + } + + void insert_equal(const value_type* __f, const value_type* __l) + { + size_type __n = __l - __f; + resize(_M_num_elements + __n); + for ( ; __n > 0; --__n, ++__f) + insert_equal_noresize(*__f); + } + + void insert_unique(const_iterator __f, const_iterator __l) + { + size_type __n = 0; + @KWSYS_NAMESPACE@_stl::distance(__f, __l, __n); + resize(_M_num_elements + __n); + for ( ; __n > 0; --__n, ++__f) + insert_unique_noresize(*__f); + } + + void insert_equal(const_iterator __f, const_iterator __l) + { + size_type __n = 0; + @KWSYS_NAMESPACE@_stl::distance(__f, __l, __n); + resize(_M_num_elements + __n); + for ( ; __n > 0; --__n, ++__f) + insert_equal_noresize(*__f); + } +#endif + + 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; + } + + @KWSYS_NAMESPACE@_stl::pair + equal_range(const key_type& __key); + + @KWSYS_NAMESPACE@_stl::pair + 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 +_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 +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 +_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 +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 +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 +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 +inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1, + hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2) { + __ht1.swap(__ht2); +} + +template +@KWSYS_NAMESPACE@_stl::pair<@KWSYS_NAMESPACE@_CXX_DECL_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 @KWSYS_NAMESPACE@_stl::pair(iterator(__cur, this), false); + + _Node* __tmp = _M_new_node(__obj); + __tmp->_M_next = __first; + _M_buckets[__n] = __tmp; + ++_M_num_elements; + return @KWSYS_NAMESPACE@_stl::pair(iterator(__tmp, this), true); +} + +template +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 +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 +@KWSYS_NAMESPACE@_stl::pair<@KWSYS_NAMESPACE@_CXX_DECL_TYPENAME hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator, + @KWSYS_NAMESPACE@_CXX_DECL_TYPENAME hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator> +hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::equal_range(const key_type& __key) +{ + typedef @KWSYS_NAMESPACE@_stl::pair _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 +@KWSYS_NAMESPACE@_stl::pair<@KWSYS_NAMESPACE@_CXX_DECL_TYPENAME hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::const_iterator, + @KWSYS_NAMESPACE@_CXX_DECL_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 @KWSYS_NAMESPACE@_stl::pair _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 +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 +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 +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 +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(__first._M_ht)), + iterator(const_cast<_Node*>(__last._M_cur), + const_cast(__last._M_ht))); +} + +template +inline void +hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::erase(const const_iterator& __it) +{ + erase(iterator(const_cast<_Node*>(__it._M_cur), + const_cast(__it._M_ht))); +} + +template +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) + @KWSYS_NAMESPACE@_HASH_BUCKETS_GET_ALLOCATOR(_M_buckets)); + 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 +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 +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 +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 +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@ + +// Normally the comparison operators should be found in the @KWSYS_NAMESPACE@ +// namespace by argument dependent lookup. For compilers that do not +// support it we must bring them into the global namespace now. +#if !@KWSYS_NAMESPACE@_CXX_HAS_ARGUMENT_DEPENDENT_LOOKUP +using @KWSYS_NAMESPACE@::operator==; +using @KWSYS_NAMESPACE@::operator!=; +#endif + +#if defined(_MSC_VER) +# pragma warning (pop) +#endif + +#endif diff --git a/kwsysHeaderDump.pl b/kwsysHeaderDump.pl new file mode 100755 index 000000000..0dc4a5204 --- /dev/null +++ b/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
\n"; + exit(1); +} + +$name = $ARGV[0]; +$max = 0; +open(INFILE, $ARGV[1]); +while (chomp ($line = )) +{ + 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/kwsysPlatformTests.cmake b/kwsysPlatformTests.cmake new file mode 100644 index 000000000..d042450ee --- /dev/null +++ b/kwsysPlatformTests.cmake @@ -0,0 +1,216 @@ +#============================================================================= +# 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("${var}_COMPILED" MATCHES "^${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} + 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(${var}_COMPILED) + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "${description} failed to compile with the following output:\n${OUTPUT}\n\n") + ENDIF(${var}_COMPILED) + IF(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + MESSAGE(STATUS "${description} - no") + ELSE(${var}_COMPILED) + MESSAGE(STATUS "${description} - yes") + ENDIF(${var}_COMPILED) + ELSE(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + MESSAGE(STATUS "${description} - yes") + ELSE(${var}_COMPILED) + MESSAGE(STATUS "${description} - no") + ENDIF(${var}_COMPILED) + ENDIF(${invert} MATCHES INVERT) + ENDIF("${var}_COMPILED" MATCHES "^${var}_COMPILED$") + IF(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + SET(${var} 0) + ELSE(${var}_COMPILED) + SET(${var} 1) + ENDIF(${var}_COMPILED) + ELSE(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + SET(${var} 1) + ELSE(${var}_COMPILED) + SET(${var} 0) + ENDIF(${var}_COMPILED) + ENDIF(${invert} MATCHES INVERT) +ENDMACRO(KWSYS_PLATFORM_TEST) + +MACRO(KWSYS_PLATFORM_TEST_RUN lang var description invert) + IF("${var}" MATCHES "^${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(${var}) + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "${description} compiled and ran with the following output:\n${OUTPUT}\n\n") + ENDIF(${var}) + ELSE(${var}_COMPILED) + 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(${var}_COMPILED) + + IF(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + IF(${var}) + MESSAGE(STATUS "${description} - yes") + ELSE(${var}) + MESSAGE(STATUS "${description} - no") + ENDIF(${var}) + ELSE(${var}_COMPILED) + MESSAGE(STATUS "${description} - failed to compile") + ENDIF(${var}_COMPILED) + ELSE(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + IF(${var}) + MESSAGE(STATUS "${description} - no") + ELSE(${var}) + MESSAGE(STATUS "${description} - yes") + ENDIF(${var}) + ELSE(${var}_COMPILED) + MESSAGE(STATUS "${description} - failed to compile") + ENDIF(${var}_COMPILED) + ENDIF(${invert} MATCHES INVERT) + ENDIF("${var}" MATCHES "^${var}$") + + IF(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + IF(${var}) + SET(${var} 1) + ELSE(${var}) + SET(${var} 0) + ENDIF(${var}) + ELSE(${var}_COMPILED) + SET(${var} 1) + ENDIF(${var}_COMPILED) + ELSE(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + IF(${var}) + SET(${var} 0) + ELSE(${var}) + SET(${var} 1) + ENDIF(${var}) + ELSE(${var}_COMPILED) + SET(${var} 0) + ENDIF(${var}_COMPILED) + ENDIF(${invert} MATCHES INVERT) +ENDMACRO(KWSYS_PLATFORM_TEST_RUN) + +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(KWSYS_PLATFORM_C_TEST) + +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(KWSYS_PLATFORM_C_TEST_RUN) + +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}) + KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}") + SET(KWSYS_PLATFORM_TEST_DEFINES) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) +ENDMACRO(KWSYS_PLATFORM_CXX_TEST) + +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_CXX_TEST_RUN) + +#----------------------------------------------------------------------------- +# 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/kwsysPlatformTestsC.c b/kwsysPlatformTestsC.c new file mode 100644 index 000000000..e602964bb --- /dev/null +++ b/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 +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 +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/kwsysPlatformTestsCXX.cxx b/kwsysPlatformTestsCXX.cxx new file mode 100644 index 000000000..7b73d06df --- /dev/null +++ b/kwsysPlatformTestsCXX.cxx @@ -0,0 +1,516 @@ +/*============================================================================ + 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. +============================================================================*/ +// Setup for tests that use result of stl namespace test. +#if defined(KWSYS_STL_HAVE_STD) +# if KWSYS_STL_HAVE_STD +# define kwsys_stl std +# else +# define kwsys_stl +# endif +#endif + +// Setup for tests that use iostreams. +#if defined(KWSYS_IOS_USE_ANSI) && defined(KWSYS_IOS_HAVE_STD) +# if defined(_MSC_VER) +# pragma warning (push,1) +# endif +# if KWSYS_IOS_USE_ANSI +# include +# else +# include +# endif +# if defined(_MSC_VER) +# pragma warning (pop) +# endif +# if KWSYS_IOS_HAVE_STD +# define kwsys_ios std +# else +# define kwsys_ios +# endif +#endif + +#ifdef TEST_KWSYS_STL_HAVE_STD +#include +void f(std ::list*) {} +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_IOS_USE_ANSI +#include +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_IOS_HAVE_STD +#include +void f(std ::ostream*) {} +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_IOS_USE_SSTREAM +#include +#if defined(__GNUC__) && __GNUC__ == 2 && __GNUC_MINOR__ == 96 +# error "GCC 2.96 stringstream is buggy" +#endif +int main() +{ + std ::ostringstream ostr; + ostr << "hello"; + if(ostr.str().size() == 5) + { + return 0; + } + return -1; +} +#endif + +#ifdef TEST_KWSYS_IOS_USE_STRSTREAM_H +#include +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_IOS_USE_STRSTREA_H +#include +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_STL_STRING_HAVE_OSTREAM +# include +# include +void f(ostream& os, const kwsys_stl::string& s) { os << s; } +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_STL_STRING_HAVE_ISTREAM +# include +# include +void f(istream& is, kwsys_stl::string& s) { is >> s; } +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_STL_STRING_HAVE_NEQ_CHAR +# include +bool f(const kwsys_stl::string& s) { return s != ""; } +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_CXX_HAS_CSTDIO +#include +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_CXX_HAS_CSTDDEF +#include +void f(size_t) {} +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(f(n)); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS___INT64 +__int64 f(__int64 n) { return n; } +int main() +{ + __int64 n = 0; + return static_cast(f(n)); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_NULL_TEMPLATE_ARGS +template class A; +template int f(A&); +template class A +{ +public: + // "friend int f<>(A&)" would conform + friend int f(A&); +private: + int x; +}; + +template int f(A& a) { return a.x = 0; } +template int f(A&); + +int main() +{ + A a; + return f(a); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_MEMBER_TEMPLATES +template +class A +{ +public: + U u; + A(): u(0) {} + template V m(V* p) { return *p = u; } +}; + +int main() +{ + A a; + int s = 1; + return a.m(&s); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_FULL_SPECIALIZATION +template struct A {}; +template <> struct A +{ + static int f() { return 0; } +}; +int main() { return A::f(); } +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ARGUMENT_DEPENDENT_LOOKUP +namespace N +{ + class A {}; + int f(A*) { return 0; } +} +void f(void*); +int main() +{ + N::A* a = 0; + return f(a); +} +#endif + +#ifdef TEST_KWSYS_STL_HAS_ITERATOR_TRAITS +#include +#include +void f(kwsys_stl::iterator_traits::iterator>::iterator_category const&) {} +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_STL_HAS_ITERATOR_CATEGORY +#include +#include +void f(kwsys_stl::list::iterator x) { kwsys_stl::iterator_category(x); } +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_STL_HAS___ITERATOR_CATEGORY +#include +#include +void f(kwsys_stl::list::iterator x) { kwsys_stl::__iterator_category(x); } +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_STL_HAS_ALLOCATOR_TEMPLATE +#include +template +void f(const Alloc&) +{ + typedef typename Alloc::size_type alloc_size_type; +} +int main() +{ + f(kwsys_stl::allocator()); + return 0; +} +#endif + +#ifdef TEST_KWSYS_STL_HAS_ALLOCATOR_NONTEMPLATE +#include +void f(kwsys_stl::allocator::size_type const&) {} +int main() { return 0; } +#endif + +#ifdef TEST_KWSYS_STL_HAS_ALLOCATOR_REBIND +#include +template +void f(const T&, const Alloc&) +{ + typedef typename Alloc::template rebind::other alloc_type; +} +int main() +{ + f(0, kwsys_stl::allocator()); + return 0; +} +#endif + +#ifdef TEST_KWSYS_STL_HAS_ALLOCATOR_MAX_SIZE_ARGUMENT +#include +void f(kwsys_stl::allocator const& a) +{ + a.max_size(sizeof(int)); +} +int main() +{ + f(kwsys_stl::allocator()); + return 0; +} +#endif + +#ifdef TEST_KWSYS_STL_HAS_ALLOCATOR_OBJECTS +#include +void f(kwsys_stl::vector const& v1) +{ + kwsys_stl::vector(1, 1, v1.get_allocator()); +} +int main() +{ + f(kwsys_stl::vector()); + return 0; +} +#endif + +#ifdef TEST_KWSYS_STAT_HAS_ST_MTIM +#include +#include +#include +int main() +{ + struct stat stat1; + (void)stat1.st_mtim.tv_sec; + (void)stat1.st_mtim.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_CAN_CONVERT_UI64_TO_DOUBLE +void function(double& l, unsigned __int64 const& r) +{ + l = static_cast(r); +} + +int main() +{ + double tTo = 0.0; + unsigned __int64 tFrom = 0; + function(tTo, tFrom); + return 0; +} +#endif + +#ifdef TEST_KWSYS_IOS_HAVE_BINARY +int test_binary(int, ...) +{ + return 0; +} +int main() +{ + return test_binary(1, kwsys_ios::ios::binary); +} +#endif + +#ifdef TEST_KWSYS_IOS_HAS_ISTREAM_LONG_LONG +int test_istream(kwsys_ios::istream& is, long long& x) +{ + return (is >> x)? 1:0; +} +int main() +{ + long long x = 0; + return test_istream(kwsys_ios::cin, x); +} +#endif + +#ifdef TEST_KWSYS_IOS_HAS_OSTREAM_LONG_LONG +int test_ostream(kwsys_ios::ostream& os, long long x) +{ + return (os << x)? 1:0; +} +int main() +{ + long long x = 0; + return test_ostream(kwsys_ios::cout, x); +} +#endif + +#ifdef TEST_KWSYS_CHAR_IS_SIGNED +/* Return 0 for char signed and 1 for char unsigned. */ +int main() +{ + unsigned char uc = 255; + return (*reinterpret_cast(&uc) < 0)?0:1; +} +#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 +#include +#include +#if KWSYS_CXX_HAS_CSTDIO +# include +#endif +#include + +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 +int main() +{ + return setenv("A", "B", 1); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UNSETENV +#include +int main() +{ + unsetenv("A"); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H +#include +int main() +{ + char* e = environ[0]; + return e? 0:1; +} +#endif + +#ifdef TEST_KWSYS_CXX_TYPE_INFO +/* Collect fundamental type information and save it to a CMake script. */ + +/* Include limits.h to get macros indicating long long and __int64. + Note that certain compilers need special macros to define these + macros in limits.h. */ +#if defined(_MSC_VER) && !defined(_MSC_EXTENSIONS) +# define _MSC_EXTENSIONS +#endif +#if defined(__GNUC__) && __GNUC__ < 3 +# define _GNU_SOURCE +#endif +#include + +#include +#include + +/* Due to shell differences and limitations of ADD_DEFINITIONS the + KWSYS_CXX_TYPE_INFO_FILE macro will sometimes have double quotes + and sometimes not. This macro will make sure the value is treated + as a double-quoted string. */ +#define TO_STRING(x) TO_STRING0(x) +#define TO_STRING0(x) TO_STRING1(x) +#define TO_STRING1(x) #x + +void f() {} + +int main() +{ + /* Construct the output file name. Some preprocessors will add an + extra level of double quotes, so strip them. */ + char fbuf[] = TO_STRING(KWSYS_CXX_TYPE_INFO_FILE); + char* fname = fbuf; + if(fname[0] == '"') + { + ++fname; + int len = static_cast(strlen(fname)); + if(len > 0 && fname[len-1] == '"') + { + fname[len-1] = 0; + } + } + + /* Try to open the output file. */ + if(FILE* fout = fopen(fname, "w")) + { + /* Set the size of standard types. */ + fprintf(fout, "SET(KWSYS_SIZEOF_CHAR %d)\n", static_cast(sizeof(char))); + fprintf(fout, "SET(KWSYS_SIZEOF_SHORT %d)\n", static_cast(sizeof(short))); + fprintf(fout, "SET(KWSYS_SIZEOF_INT %d)\n", static_cast(sizeof(int))); + fprintf(fout, "SET(KWSYS_SIZEOF_LONG %d)\n", static_cast(sizeof(long))); + + /* Set the size of some non-standard but common types. */ + /* Check for a limits.h macro for long long to see if the type exists. */ +#if defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX) + fprintf(fout, "SET(KWSYS_SIZEOF_LONG_LONG %d)\n", static_cast(sizeof(long long))); +#else + fprintf(fout, "SET(KWSYS_SIZEOF_LONG_LONG 0) # No long long available.\n"); +#endif + /* Check for a limits.h macro for __int64 to see if the type exists. */ +#if defined(_I64_MIN) + fprintf(fout, "SET(KWSYS_SIZEOF___INT64 %d)\n", static_cast(sizeof(__int64))); +#else + fprintf(fout, "SET(KWSYS_SIZEOF___INT64 0) # No __int64 available.\n"); +#endif + + /* Set the size of some pointer types. */ + fprintf(fout, "SET(KWSYS_SIZEOF_PDATA %d)\n", static_cast(sizeof(void*))); + fprintf(fout, "SET(KWSYS_SIZEOF_PFUNC %d)\n", static_cast(sizeof(&f))); + + /* Set whether the native type "char" is signed or unsigned. */ + unsigned char uc = 255; + fprintf(fout, "SET(KWSYS_CHAR_IS_SIGNED %d)\n", + (*reinterpret_cast(&uc) < 0)?1:0); + + fclose(fout); + return 0; + } + else + { + fprintf(stderr, "Failed to write fundamental type info to \"%s\".\n", + fname); + return 1; + } +} +#endif diff --git a/kwsysPrivate.h b/kwsysPrivate.h new file mode 100644 index 000000000..3a26c26fb --- /dev/null +++ b/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) + +/* + 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/kwsys_cstddef.hxx.in b/kwsys_cstddef.hxx.in new file mode 100644 index 000000000..925c03084 --- /dev/null +++ b/kwsys_cstddef.hxx.in @@ -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. +============================================================================*/ +#ifndef @KWSYS_NAMESPACE@_cstddef +#define @KWSYS_NAMESPACE@_cstddef + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +/* Avoid warnings in MSVC standard headers. */ +#ifdef _MSC_VER +# pragma warning (push, 1) +# pragma warning (disable: 4702) +# pragma warning (disable: 4786) +#endif + +/* Include the real header. */ +#if @KWSYS_NAMESPACE@_CXX_HAS_CSTDDEF +# include +#else +# include +#endif + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif diff --git a/kwsys_ios_fstream.h.in b/kwsys_ios_fstream.h.in new file mode 100644 index 000000000..4b1a8cfcc --- /dev/null +++ b/kwsys_ios_fstream.h.in @@ -0,0 +1,46 @@ +/*============================================================================ + 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@_ios_fstream +#define @KWSYS_NAMESPACE@_ios_fstream + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#ifdef _MSC_VER +# pragma warning (push, 1) +# pragma warning (disable: 4702) +# pragma warning (disable: 4995) /* Old streams are deprecated. */ +#endif + +#if @KWSYS_NAMESPACE@_IOS_USE_ANSI +# include +#else +# include +#endif + +#if !@KWSYS_NAMESPACE@_IOS_USE_SSTREAM +namespace @KWSYS_NAMESPACE@_ios +{ + using @KWSYS_NAMESPACE@_ios_namespace::ostream; + using @KWSYS_NAMESPACE@_ios_namespace::istream; + using @KWSYS_NAMESPACE@_ios_namespace::ofstream; + using @KWSYS_NAMESPACE@_ios_namespace::ifstream; + using @KWSYS_NAMESPACE@_ios_namespace::ios; + using @KWSYS_NAMESPACE@_ios_namespace::endl; + using @KWSYS_NAMESPACE@_ios_namespace::flush; +} +#endif + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif diff --git a/kwsys_ios_iosfwd.h.in b/kwsys_ios_iosfwd.h.in new file mode 100644 index 000000000..f4fafebc2 --- /dev/null +++ b/kwsys_ios_iosfwd.h.in @@ -0,0 +1,49 @@ +/*============================================================================ + 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@_ios_iosfwd +#define @KWSYS_NAMESPACE@_ios_iosfwd + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#ifdef _MSC_VER +#pragma warning (push, 1) +#pragma warning (disable: 4702) +#endif + +#if @KWSYS_NAMESPACE@_IOS_USE_ANSI +# include +#else +class fstream; +class ifstream; +class ios; +class istream; +class ofstream; +class ostream; +#endif + +#if !@KWSYS_NAMESPACE@_IOS_USE_SSTREAM +namespace @KWSYS_NAMESPACE@_ios +{ + using @KWSYS_NAMESPACE@_ios_namespace::fstream; + using @KWSYS_NAMESPACE@_ios_namespace::ifstream; + using @KWSYS_NAMESPACE@_ios_namespace::ios; + using @KWSYS_NAMESPACE@_ios_namespace::istream; + using @KWSYS_NAMESPACE@_ios_namespace::ofstream; + using @KWSYS_NAMESPACE@_ios_namespace::ostream; +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/kwsys_ios_iostream.h.in b/kwsys_ios_iostream.h.in new file mode 100644 index 000000000..43fc4d579 --- /dev/null +++ b/kwsys_ios_iostream.h.in @@ -0,0 +1,99 @@ +/*============================================================================ + 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@_ios_iostream +#define @KWSYS_NAMESPACE@_ios_iostream + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#ifdef _MSC_VER +# pragma warning (push, 1) +# pragma warning (disable: 4702) +# pragma warning (disable: 4995) /* Old streams are deprecated. */ +#endif + +#if @KWSYS_NAMESPACE@_IOS_USE_ANSI +# include +#else +# include +#endif + +// The HP implementation of iostream defines cin, cout, cerr, and clog +// as macros in order to do thread-private streams. +// See /opt/aCC/include/iostream/iostream.h for details. +// This block redefines the macros in a safe way that is also compatible +// with the HP definitions and the using declarations below. + +#if !@KWSYS_NAMESPACE@_IOS_USE_SSTREAM +# if defined(__HP_aCC) && (defined(HP_THREAD_SAFE) || defined(_THREAD_SAFE)) +# if defined(cin) && !defined(@KWSYS_NAMESPACE@_IOS_HP_HACK_CIN) +# define @KWSYS_NAMESPACE@_IOS_HP_HACK_CIN +# undef cin +# define cin __tcin.ref() +# endif +# if defined(cout) && !defined(@KWSYS_NAMESPACE@_IOS_HP_HACK_COUT) +# define @KWSYS_NAMESPACE@_IOS_HP_HACK_COUT +# undef cout +# define cout __tcout.ref() +# endif +# if defined(cerr) && !defined(@KWSYS_NAMESPACE@_IOS_HP_HACK_CERR) +# define @KWSYS_NAMESPACE@_IOS_HP_HACK_CERR +# undef cerr +# define cerr __tcerr.ref() +# endif +# if defined(clog) && !defined(@KWSYS_NAMESPACE@_IOS_HP_HACK_CLOG) +# define @KWSYS_NAMESPACE@_IOS_HP_HACK_CLOG +# undef clog +# define clog __tclog.ref() +# endif +# endif +#endif + +// If using our own sstream emulation code, put the standard +// streams in the same namespace. +#if !@KWSYS_NAMESPACE@_IOS_USE_SSTREAM +namespace @KWSYS_NAMESPACE@_ios +{ + typedef int streamsize; + typedef int streamoff; + using @KWSYS_NAMESPACE@_ios_namespace::ostream; + using @KWSYS_NAMESPACE@_ios_namespace::istream; + using @KWSYS_NAMESPACE@_ios_namespace::ios; + using @KWSYS_NAMESPACE@_ios_namespace::endl; + using @KWSYS_NAMESPACE@_ios_namespace::flush; +# if defined(@KWSYS_NAMESPACE@_IOS_HP_HACK_CIN) + using @KWSYS_NAMESPACE@_ios_namespace::__tcin; +# else + using @KWSYS_NAMESPACE@_ios_namespace::cin; +# endif +# if defined(@KWSYS_NAMESPACE@_IOS_HP_HACK_COUT) + using @KWSYS_NAMESPACE@_ios_namespace::__tcout; +# else + using @KWSYS_NAMESPACE@_ios_namespace::cout; +# endif +# if defined(@KWSYS_NAMESPACE@_IOS_HP_HACK_CERR) + using @KWSYS_NAMESPACE@_ios_namespace::__tcerr; +# else + using @KWSYS_NAMESPACE@_ios_namespace::cerr; +# endif +# if defined(@KWSYS_NAMESPACE@_IOS_HP_HACK_CLOG) + using @KWSYS_NAMESPACE@_ios_namespace::__tclog; +# else + using @KWSYS_NAMESPACE@_ios_namespace::clog; +# endif +} +#endif + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif diff --git a/kwsys_ios_sstream.h.in b/kwsys_ios_sstream.h.in new file mode 100644 index 000000000..29d250c7a --- /dev/null +++ b/kwsys_ios_sstream.h.in @@ -0,0 +1,199 @@ +/*============================================================================ + 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@_ios_sstream +#define @KWSYS_NAMESPACE@_ios_sstream + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +/* Define this macro temporarily to keep the code readable. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsys_stl @KWSYS_NAMESPACE@_stl +#endif + +#if @KWSYS_NAMESPACE@_IOS_USE_SSTREAM +# ifdef _MSC_VER +# pragma warning (push, 1) +# pragma warning (disable: 4702) +# endif +# include +# ifdef _MSC_VER +# pragma warning(pop) +# endif +#else +# ifdef _MSC_VER +# pragma warning (push, 1) +# pragma warning (disable: 4702) +# pragma warning (disable: 4995) /* Old streams are deprecated. */ +# endif +# if @KWSYS_NAMESPACE@_IOS_USE_ANSI +# include +# elif @KWSYS_NAMESPACE@_IOS_USE_STRSTREAM_H +# include +# elif @KWSYS_NAMESPACE@_IOS_USE_STRSTREA_H +# include +# endif +# if @KWSYS_NAMESPACE@_IOS_USE_ANSI +# include // Need placement operator new. +# else +# include // Need placement operator new. +# endif +# ifdef _MSC_VER +# pragma warning(pop) +# endif + +// Only have old std strstream classes. Wrap them to look like new +// ostringstream and istringstream classes. + +# include <@KWSYS_NAMESPACE@/stl/string> + +namespace @KWSYS_NAMESPACE@_ios +{ +using @KWSYS_NAMESPACE@_ios_namespace::streambuf; +using @KWSYS_NAMESPACE@_ios_namespace::ostream; +using @KWSYS_NAMESPACE@_ios_namespace::istream; +using @KWSYS_NAMESPACE@_ios_namespace::strstream; +using @KWSYS_NAMESPACE@_ios_namespace::istrstream; +using @KWSYS_NAMESPACE@_ios_namespace::ostrstream; +using @KWSYS_NAMESPACE@_ios_namespace::ios; +using @KWSYS_NAMESPACE@_ios_namespace::endl; +using @KWSYS_NAMESPACE@_ios_namespace::ends; +using @KWSYS_NAMESPACE@_ios_namespace::flush; + +class stringstream_cleanup +{ +public: + stringstream_cleanup(strstream& str): m_StrStream(str) {} + ~stringstream_cleanup() { m_StrStream.rdbuf()->freeze(0); } + static void IgnoreUnusedVariable(const stringstream_cleanup&) {} +protected: + strstream& m_StrStream; +private: + void operator=(stringstream_cleanup const&); +}; + +class stringstream: public strstream +{ +public: + typedef strstream Superclass; + stringstream() {} + stringstream(const kwsys_stl::string& s) { *this << s.c_str(); } + kwsys_stl::string str() + { + stringstream_cleanup cleanup(*this); + stringstream_cleanup::IgnoreUnusedVariable(cleanup); +// Visual Studio 6 has a strstream::pcount, but this is not rdbuf()->pcount() +#if (@KWSYS_NAMESPACE@_IOS_USE_STRSTREA_H) && defined(_MSC_VER) && (_MSC_VER == 1200) + int count = this->pcount(); +#elif defined(__WATCOMC__) + int count = this->rdbuf()->out_waiting(); +#else + int count = this->rdbuf()->pcount(); +#endif + const char* ptr = this->Superclass::str(); + return kwsys_stl::string(ptr?ptr:"", count); + } + void str(const kwsys_stl::string& s) + { + this->~stringstream(); + new (this) stringstream(s); + } +private: + stringstream(const stringstream&); + void operator=(const stringstream&); +}; + +class ostringstream_cleanup +{ +public: + ostringstream_cleanup(ostrstream& ostr): m_OStrStream(ostr) {} + ~ostringstream_cleanup() { m_OStrStream.rdbuf()->freeze(0); } + static void IgnoreUnusedVariable(const ostringstream_cleanup&) {} +protected: + ostrstream& m_OStrStream; +private: + void operator=(ostringstream_cleanup const&); +}; + +class ostringstream: public ostrstream +{ +public: + typedef ostrstream Superclass; + ostringstream() {} + ostringstream(const kwsys_stl::string& s) { *this << s.c_str(); } + kwsys_stl::string str() + { + ostringstream_cleanup cleanup(*this); + ostringstream_cleanup::IgnoreUnusedVariable(cleanup); + int count = this->pcount(); + const char* ptr = this->Superclass::str(); + return kwsys_stl::string(ptr?ptr:"", count); + } + void str(const kwsys_stl::string& s) + { + this->~ostringstream(); + new (this) ostringstream(s); + } +private: + ostringstream(const ostringstream&); + void operator=(const ostringstream&); +}; + +#if defined(_MSC_VER) +# pragma warning (push) +# pragma warning (disable: 4097) /* typedef-name used as synonym for class */ +#endif +#if defined(__WATCOMC__) +// W728: class modifiers for 'A' conflict with class modifiers for 'B' +# pragma warning 728 10 +#endif + +class istringstream: private kwsys_stl::string, public istrstream +{ +public: + typedef kwsys_stl::string StdString; + typedef istrstream IStrStream; + istringstream(): StdString(), + IStrStream(const_cast(StdString::c_str())) {} + istringstream(const kwsys_stl::string& s): + StdString(s), IStrStream(const_cast(StdString::c_str())) {} + kwsys_stl::string str() const { return *this; } + void str(const kwsys_stl::string& s) + { + this->~istringstream(); + new (this) istringstream(s); + } + void clear(int flags) + { + this->IStrStream::clear(flags); + } +private: + istringstream(const istringstream&); + void operator=(const istringstream&); +}; + +#if defined(__WATCOMC__) +# pragma warning 728 9 +#endif +#if defined(_MSC_VER) +# pragma warning (pop) +#endif + +} // namespace @KWSYS_NAMESPACE@_ios + +#endif + +/* Undefine temporary macro. */ +#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsys_stl +#endif + +#endif diff --git a/kwsys_stl.hxx.in b/kwsys_stl.hxx.in new file mode 100644 index 000000000..610e6d471 --- /dev/null +++ b/kwsys_stl.hxx.in @@ -0,0 +1,49 @@ +/*============================================================================ + 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@_stl_@KWSYS_STL_HEADER@ +#define @KWSYS_NAMESPACE@_stl_@KWSYS_STL_HEADER@ + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +/* Avoid warnings in MSVC standard headers. */ +#ifdef _MSC_VER +# pragma warning (push, 1) +# pragma warning (disable: 4702) +# pragma warning (disable: 4786) +#endif + +/* The HP standard library defines the functor "times" instead of + "multiplies" as specified by C++98 20.3.2 for backward + compatibility with earlier specifications. Defining this macro + fixes this behavior. The name "times" also conflicts with the + function declared in sys/times.h on that platform, so we must do + this as a work-around anyway. */ +#if defined(__HP_aCC) && !defined(__HPACC_USING_MULTIPLIES_IN_FUNCTIONAL) +# define __HPACC_USING_MULTIPLIES_IN_FUNCTIONAL +# define @KWSYS_NAMESPACE@_DEFINED___HPACC_USING_MULTIPLIES_IN_FUNCTIONAL +#endif + +/* Include the real header. */ +#include <@KWSYS_STL_HEADER@> + +/* Cleanup. */ +#if defined(@KWSYS_NAMESPACE@_DEFINED___HPACC_USING_MULTIPLIES_IN_FUNCTIONAL) +# undef @KWSYS_NAMESPACE@_DEFINED___HPACC_USING_MULTIPLIES_IN_FUNCTIONAL +# undef __HPACC_USING_MULTIPLIES_IN_FUNCTIONAL +#endif + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +@KWSYS_STL_HEADER_EXTRA@ +#endif diff --git a/kwsys_stl_string.hxx.in b/kwsys_stl_string.hxx.in new file mode 100644 index 000000000..cd312cb8e --- /dev/null +++ b/kwsys_stl_string.hxx.in @@ -0,0 +1,123 @@ +/*============================================================================ + 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. +============================================================================*/ + +// This header is extra code for <@KWSYS_NAMESPACE@/stl/string>. +#if !defined(@KWSYS_NAMESPACE@_stl_string_including_hxx) +# error "The header <@KWSYS_NAMESPACE@/stl/string.hxx> may be included only by <@KWSYS_NAMESPACE@/stl/string>." +#endif + +// Provide the istream operator for the stl string if it is not +// provided by the system or another copy of kwsys. Allow user code +// to block this definition by defining the macro +// @KWSYS_NAMESPACE@_STL_STRING_NO_ISTREAM +// to avoid conflicts with other libraries. User code can test for +// this definition by checking the macro +// @KWSYS_NAMESPACE@_STL_STRING_ISTREAM_DEFINED +#if !@KWSYS_NAMESPACE@_STL_STRING_HAVE_ISTREAM && !defined(@KWSYS_NAMESPACE@_STL_STRING_NO_ISTREAM) && !defined(KWSYS_STL_STRING_ISTREAM_DEFINED) +# define KWSYS_STL_STRING_ISTREAM_DEFINED +# define @KWSYS_NAMESPACE@_STL_STRING_ISTREAM_DEFINED +# include // isspace +# include <@KWSYS_NAMESPACE@/ios/iostream> +# if defined(__WATCOMC__) +namespace @KWSYS_NAMESPACE@ +{ +struct ios_istream_hack: public kwsys_ios::istream +{ void eatwhite() { this->@KWSYS_NAMESPACE@_ios::istream::eatwhite(); } }; +} +# endif +inline @KWSYS_NAMESPACE@_ios::istream& +operator>>(@KWSYS_NAMESPACE@_ios::istream& is, + @KWSYS_NAMESPACE@_stl::string& s) +{ + // Keep track of the resulting state. + int state = @KWSYS_NAMESPACE@_ios::ios::goodbit; + + // Save the width setting and set it back to zero. + size_t n = static_cast(is.width(0)); + + // Clear any old contents of the output string. + s.erase(); + + // Skip leading whitespace. +#if defined(__WATCOMC__) + static_cast<@KWSYS_NAMESPACE@::ios_istream_hack&>(is).eatwhite(); +#else + is.eatwhite(); +#endif + @KWSYS_NAMESPACE@_ios::istream& okay = is; + + if(okay) + { + // Select a maximum possible length. + if(n == 0 || n >= s.max_size()) + { + n = s.max_size(); + } + + // Read until a space is found or the maximum length is reached. + bool success = false; + for(int c = is.peek(); (--n > 0 && c != EOF && !isspace(c)); c = is.peek()) + { + s += static_cast(c); + success = true; + is.ignore(); + } + + // Set flags for resulting state. + if(is.peek() == EOF) { state |= @KWSYS_NAMESPACE@_ios::ios::eofbit; } + if(!success) { state |= @KWSYS_NAMESPACE@_ios::ios::failbit; } + } + + // Set the final result state. + is.clear(state); + return is; +} +#endif + +// Provide the ostream operator for the stl string if it is not +// provided by the system or another copy of kwsys. Allow user code +// to block this definition by defining the macro +// @KWSYS_NAMESPACE@_STL_STRING_NO_OSTREAM +// to avoid conflicts with other libraries. User code can test for +// this definition by checking the macro +// @KWSYS_NAMESPACE@_STL_STRING_OSTREAM_DEFINED +#if !@KWSYS_NAMESPACE@_STL_STRING_HAVE_OSTREAM && !defined(@KWSYS_NAMESPACE@_STL_STRING_NO_OSTREAM) && !defined(KWSYS_STL_STRING_OSTREAM_DEFINED) +# define KWSYS_STL_STRING_OSTREAM_DEFINED +# define @KWSYS_NAMESPACE@_STL_STRING_OSTREAM_DEFINED +# include <@KWSYS_NAMESPACE@/ios/iostream> +inline @KWSYS_NAMESPACE@_ios::ostream& +operator<<(@KWSYS_NAMESPACE@_ios::ostream& os, + @KWSYS_NAMESPACE@_stl::string const& s) +{ + return os << s.c_str(); +} +#endif + +// Provide the operator!= for the stl string and char* if it is not +// provided by the system or another copy of kwsys. Allow user code +// to block this definition by defining the macro +// @KWSYS_NAMESPACE@_STL_STRING_NO_NEQ_CHAR +// to avoid conflicts with other libraries. User code can test for +// this definition by checking the macro +// @KWSYS_NAMESPACE@_STL_STRING_NEQ_CHAR_DEFINED +#if !@KWSYS_NAMESPACE@_STL_STRING_HAVE_NEQ_CHAR && !defined(@KWSYS_NAMESPACE@_STL_STRING_NO_NEQ_CHAR) && !defined(KWSYS_STL_STRING_NEQ_CHAR_DEFINED) +# define KWSYS_STL_STRING_NEQ_CHAR_DEFINED +# define @KWSYS_NAMESPACE@_STL_STRING_NEQ_CHAR_DEFINED +inline bool operator!=(@KWSYS_NAMESPACE@_stl::string const& s, const char* c) +{ + return !(s == c); +} +inline bool operator!=(const char* c, @KWSYS_NAMESPACE@_stl::string const& s) +{ + return !(s == c); +} +#endif diff --git a/testAutoPtr.cxx b/testAutoPtr.cxx new file mode 100644 index 000000000..ed75ff447 --- /dev/null +++ b/testAutoPtr.cxx @@ -0,0 +1,166 @@ +/*============================================================================ + 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 __BORLANDC__ +# pragma warn -8027 /* 'for' not inlined. */ +# pragma warn -8026 /* exception not inlined. */ +#endif +#include "kwsysPrivate.h" +#include KWSYS_HEADER(auto_ptr.hxx) +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "auto_ptr.hxx.in" +#endif + +#include + +#define ASSERT(x,y) if (!(x)) { printf("FAIL: " y "\n"); status = 1; } + +int instances = 0; // don't declare as static + +struct A +{ + A() { ++instances; } + ~A() { --instances; } + A* self() {return this; } +}; +struct B: public A {}; + +static int function_call(kwsys::auto_ptr a) +{ + return a.get()? 1:0; +} + +static A* get_A(A& a) { return &a; } + +static kwsys::auto_ptr generate_auto_ptr_A() +{ + return kwsys::auto_ptr(new A); +} + +static kwsys::auto_ptr generate_auto_ptr_B() +{ + return kwsys::auto_ptr(new B); +} + +int testAutoPtr(int, char*[]) +{ + int status = 0; + + // Keep everything in a subscope so we can detect leaks. + { + kwsys::auto_ptr pa0; + kwsys::auto_ptr pa1(new A()); + kwsys::auto_ptr pb1(new B()); + kwsys::auto_ptr pb2(new B()); + kwsys::auto_ptr pa2(new B()); + + A* ptr = get_A(*pa1); + ASSERT(ptr == pa1.get(), + "auto_ptr does not return correct object when dereferenced"); + ptr = pa1->self(); + ASSERT(ptr == pa1.get(), + "auto_ptr does not return correct pointer from operator->"); + + A* before = pa0.get(); + pa0.reset(new A()); + ASSERT(pa0.get() && pa0.get() != before, + "auto_ptr empty after reset(new A())"); + + before = pa0.get(); + pa0.reset(new B()); + ASSERT(pa0.get() && pa0.get() != before, + "auto_ptr empty after reset(new B())"); + + delete pa0.release(); + ASSERT(!pa0.get(), "auto_ptr holds an object after release()"); + + kwsys::auto_ptr pa3(pb1); + ASSERT(!pb1.get(), + "auto_ptr full after being used to construct another"); + ASSERT(pa3.get(), + "auto_ptr empty after construction from another"); + + { + kwsys::auto_ptr pa; + pa = pa3; + ASSERT(!pa3.get(), + "auto_ptr full after assignment to another"); + ASSERT(pa.get(), + "auto_ptr empty after assignment from another"); + } + + { + kwsys::auto_ptr pa; + pa = pb2; + ASSERT(!pb2.get(), + "auto_ptr full after assignment to compatible"); + ASSERT(pa.get(), + "auto_ptr empty after assignment from compatible"); + } + + { + int receive = function_call(pa2); + ASSERT(receive, + "auto_ptr did not receive ownership in called function"); + ASSERT(!pa2.get(), + "auto_ptr did not release ownership to called function"); + } + + { + int received = function_call(generate_auto_ptr_A()); + ASSERT(received, + "auto_ptr in called function did not take ownership " + "from factory function"); + } + +#if 0 + // Is this allowed by the standard? + { + int received = function_call(generate_auto_ptr_B()); + ASSERT(received, + "auto_ptr in called function did not take ownership " + "from factory function with conversion"); + } +#endif + + { + kwsys::auto_ptr pa(generate_auto_ptr_A()); + ASSERT(pa.get(), + "auto_ptr empty after construction from factory function"); + } + + { + kwsys::auto_ptr pa; + pa = generate_auto_ptr_A(); + ASSERT(pa.get(), + "auto_ptr empty after assignment from factory function"); + } + + { + kwsys::auto_ptr pa(generate_auto_ptr_B()); + ASSERT(pa.get(), + "auto_ptr empty after construction from compatible factory function"); + } + + { + kwsys::auto_ptr pa; + pa = generate_auto_ptr_B(); + ASSERT(pa.get(), + "auto_ptr empty after assignment from compatible factory function"); + } + } + + ASSERT(instances == 0, "auto_ptr leaked an object"); + + return status; +} diff --git a/testCommandLineArguments.cxx b/testCommandLineArguments.cxx new file mode 100644 index 000000000..e75a87e86 --- /dev/null +++ b/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) +#include KWSYS_HEADER(ios/iostream) +#include KWSYS_HEADER(stl/vector) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "CommandLineArguments.hxx.in" +# include "kwsys_ios_iostream.h.in" +#endif + +#include /* size_t */ +#include /* strcmp */ + +void* random_ptr = reinterpret_cast(0x123); + +int argument(const char* arg, const char* value, void* call_data) +{ + kwsys_ios::cout << "Got argument: \"" << arg << "\" value: \"" << (value?value:"(null)") << "\"" << kwsys_ios::endl; + if ( call_data != random_ptr ) + { + kwsys_ios::cerr << "Problem processing call_data" << kwsys_ios::endl; + return 0; + } + return 1; +} + +int unknown_argument(const char* argument, void* call_data) +{ + kwsys_ios::cout << "Got unknown argument: \"" << argument << "\"" << kwsys_ios::endl; + if ( call_data != random_ptr ) + { + kwsys_ios::cerr << "Problem processing call_data" << kwsys_ios::endl; + return 0; + } + return 1; +} + +bool CompareTwoItemsOnList(bool i1, bool i2) { return i1 == i2; } +bool CompareTwoItemsOnList(int i1, int i2) { return i1 == i2; } +bool CompareTwoItemsOnList(double i1, double i2) { return i1 == i2; } +bool CompareTwoItemsOnList(const char* i1, + const char* i2) { return strcmp(i1, i2) == 0; } +bool CompareTwoItemsOnList(const kwsys_stl::string& i1, + const kwsys_stl::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; + kwsys_stl::string some_stl_string_variable = ""; + bool some_bool_variable = false; + bool some_bool_variable1 = false; + bool bool_arg1 = false; + int bool_arg2 = 0; + + kwsys_stl::vector numbers_argument; + int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 }; + + kwsys_stl::vector doubles_argument; + double valid_doubles[] = { 12.5, 1.31, 22 }; + + kwsys_stl::vector bools_argument; + bool valid_bools[] = { true, true, false }; + + kwsys_stl::vector strings_argument; + const char* valid_strings[] = { "andy", "bill", "brad", "ken" }; + + kwsys_stl::vector stl_strings_argument; + kwsys_stl::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() ) + { + kwsys_ios::cerr << "Problem parsing arguments" << kwsys_ios::endl; + res = 1; + } + kwsys_ios::cout << "Help: " << arg.GetHelp() << kwsys_ios::endl; + + kwsys_ios::cout << "Some int variable was set to: " << some_int_variable << kwsys_ios::endl; + kwsys_ios::cout << "Some double variable was set to: " << some_double_variable << kwsys_ios::endl; + if ( some_string_variable && strcmp(some_string_variable, "test string with space") == 0) + { + kwsys_ios::cout << "Some string variable was set to: " << some_string_variable << kwsys_ios::endl; + delete [] some_string_variable; + } + else + { + kwsys_ios::cerr << "Problem setting string variable" << kwsys_ios::endl; + res = 1; + } + size_t cc; +#define CompareTwoLists(list1, list_valid, lsize) \ + if ( list1.size() != lsize ) \ + { \ + kwsys_ios::cerr << "Problem setting " #list1 ". Size is: " << list1.size() \ + << " should be: " << lsize << kwsys_ios::endl; \ + res = 1; \ + } \ + else \ + { \ + kwsys_ios::cout << #list1 " argument set:"; \ + for ( cc =0; cc < lsize; ++ cc ) \ + { \ + kwsys_ios::cout << " " << list1[cc]; \ + if ( !CompareTwoItemsOnList(list1[cc], list_valid[cc]) ) \ + { \ + kwsys_ios::cerr << "Problem setting " #list1 ". Value of " \ + << cc << " is: [" << list1[cc] << "] <> [" \ + << list_valid[cc] << "]" << kwsys_ios::endl; \ + res = 1; \ + break; \ + } \ + } \ + kwsys_ios::cout << kwsys_ios::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); + + kwsys_ios::cout << "Some STL String variable was set to: " << some_stl_string_variable.c_str() << kwsys_ios::endl; + kwsys_ios::cout << "Some bool variable was set to: " << some_bool_variable << kwsys_ios::endl; + kwsys_ios::cout << "Some bool variable was set to: " << some_bool_variable1 << kwsys_ios::endl; + kwsys_ios::cout << "bool_arg1 variable was set to: " << bool_arg1 << kwsys_ios::endl; + kwsys_ios::cout << "bool_arg2 variable was set to: " << bool_arg2 << kwsys_ios::endl; + kwsys_ios::cout << kwsys_ios::endl; + + for ( cc = 0; cc < strings_argument.size(); ++ cc ) + { + delete [] strings_argument[cc]; + strings_argument[cc] = 0; + } + return res; +} diff --git a/testCommandLineArguments1.cxx b/testCommandLineArguments1.cxx new file mode 100644 index 000000000..0860c2abc --- /dev/null +++ b/testCommandLineArguments1.cxx @@ -0,0 +1,106 @@ +/*============================================================================ + 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(ios/iostream) +#include KWSYS_HEADER(stl/vector) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "CommandLineArguments.hxx.in" +# include "kwsys_ios_iostream.h.in" +#endif + +#include /* strcmp */ + +int testCommandLineArguments1(int argc, char* argv[]) +{ + kwsys::CommandLineArguments arg; + arg.Initialize(argc, argv); + + int n = 0; + char* m = 0; + kwsys_stl::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() ) + { + kwsys_ios::cerr << "Problem parsing arguments" << kwsys_ios::endl; + res = 1; + } + if ( n != 24 ) + { + kwsys_ios::cout << "Problem setting N. Value of N: " << n << kwsys_ios::endl; + res = 1; + } + if ( !m || strcmp(m, "test value") != 0 ) + { + kwsys_ios::cout << "Problem setting M. Value of M: " << m << kwsys_ios::endl; + res = 1; + } + if ( p != "1" ) + { + kwsys_ios::cout << "Problem setting P. Value of P: " << p.c_str() << kwsys_ios::endl; + res = 1; + } + kwsys_ios::cout << "Value of N: " << n << kwsys_ios::endl; + kwsys_ios::cout << "Value of M: " << m << kwsys_ios::endl; + kwsys_ios::cout << "Value of P: " << p.c_str() << kwsys_ios::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 ) + { + kwsys_ios::cerr << "Bad number of unused arguments: " << newArgc << kwsys_ios::endl; + res = 1; + } + for ( cc = 0; cc < newArgc; ++ cc ) + { + kwsys_ios::cout << "Unused argument[" << cc << "] = [" << newArgv[cc] << "]" + << kwsys_ios::endl; + if ( cc >= 9 ) + { + kwsys_ios::cerr << "Too many unused arguments: " << cc << kwsys_ios::endl; + res = 1; + } + else if ( valid_unused_args[cc] && + strcmp(valid_unused_args[cc], newArgv[cc]) != 0 ) + { + kwsys_ios::cerr << "Bad unused argument [" << cc << "] \"" + << newArgv[cc] << "\" should be: \"" << valid_unused_args[cc] << "\"" + << kwsys_ios::endl; + res = 1; + } + } + arg.DeleteRemainingArguments(newArgc, &newArgv); + + return res; +} + diff --git a/testDynamicLoader.cxx b/testDynamicLoader.cxx new file mode 100644 index 000000000..a7adbcad9 --- /dev/null +++ b/testDynamicLoader.cxx @@ -0,0 +1,133 @@ +/*============================================================================ + 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(ios/iostream) +#include KWSYS_HEADER(stl/string) + +#if defined(__BEOS__) && !defined(__HAIKU__) +#include /* disable_debugger() API. */ +#endif + +#if defined(__HAIKU__) +#include /* disable_debugger() API. */ +#endif + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "DynamicLoader.hxx.in" +# include "kwsys_ios_iostream.h.in" +# include "kwsys_stl_string.hxx.in" +#endif + +// Include with <> instead of "" to avoid getting any in-source copy +// left on disk. +#include + +kwsys_stl::string GetLibName(const char* lname) +{ + // Construct proper name of lib + kwsys_stl::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 ? + */ +int TestDynamicLoader(const char* libname, const char* symbol, int r1, int r2, int r3) +{ + kwsys_ios::cerr << "Testing: " << libname << kwsys_ios::endl; + kwsys::DynamicLoader::LibraryHandle l + = kwsys::DynamicLoader::OpenLibrary(libname); + // If result is incompatible with expectation just fails (xor): + if( (r1 && !l) || (!r1 && l) ) + { + kwsys_ios::cerr + << kwsys::DynamicLoader::LastError() << kwsys_ios::endl; + return 1; + } + kwsys::DynamicLoader::SymbolPointer f + = kwsys::DynamicLoader::GetSymbolAddress(l, symbol); + if( (r2 && !f) || (!r2 && f) ) + { + kwsys_ios::cerr + << kwsys::DynamicLoader::LastError() << kwsys_ios::endl; + return 1; + } +#ifndef __APPLE__ + int s = kwsys::DynamicLoader::CloseLibrary(l); + if( (r3 && !s) || (!r3 && s) ) + { + kwsys_ios::cerr + << kwsys::DynamicLoader::LastError() << kwsys_ios::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 inexistant lib is giving correct result + res += TestDynamicLoader("azerty_", "foo_bar",0,0,0); + // Make sure that random binary file cannnot be assimilated as dylib + res += TestDynamicLoader(TEST_SYSTEMTOOLS_BIN_FILE, "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 + kwsys_stl::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/testDynload.c b/testDynload.c new file mode 100644 index 000000000..ba60becbd --- /dev/null +++ b/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/testEncode.c b/testEncode.c new file mode 100644 index 000000000..26d483b6f --- /dev/null +++ b/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 +#include + +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/testFail.c b/testFail.c new file mode 100644 index 000000000..7e062c175 --- /dev/null +++ b/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 +#include +#include + +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/testHashSTL.cxx b/testHashSTL.cxx new file mode 100644 index 000000000..b861a5b32 --- /dev/null +++ b/testHashSTL.cxx @@ -0,0 +1,75 @@ +/*============================================================================ + 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) +#include KWSYS_HEADER(ios/iostream) + +// 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" +# include "hashtable.hxx.in" +# include "kwsys_ios_iostream.h.in" +#endif + +#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; +template class kwsys::hash_set; + +bool test_hash_map() +{ + typedef kwsys::hash_map 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) + { + kwsys_ios::cout << "Found entry [" << mi->first << "," << mi->second << "]" + << kwsys_ios::endl; + sum += mi->second; + } + return sum == 3; +} + +bool test_hash_set() +{ + typedef kwsys::hash_set stype; + stype s; + s.insert(1); + s.insert(2); + int sum = 0; + for(stype::iterator si = s.begin(); si != s.end(); ++si) + { + kwsys_ios::cout << "Found entry [" << *si << "]" << kwsys_ios::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/testIOS.cxx b/testIOS.cxx new file mode 100644 index 000000000..3b971e268 --- /dev/null +++ b/testIOS.cxx @@ -0,0 +1,167 @@ +/*============================================================================ + 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(stl/vector) +#include KWSYS_HEADER(ios/sstream) +#include KWSYS_HEADER(ios/fstream) +#include KWSYS_HEADER(ios/iostream) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "kwsys_stl_string.hxx.in" +# include "kwsys_stl_vector.h.in" +# include "kwsys_ios_sstream.h.in" +# include "kwsys_ios_fstream.h.in" +# include "kwsys_ios_iostream.h.in" +#endif + +#include /* strlen */ + +int testIOS(int, char*[]) +{ + kwsys_ios::ostringstream ostr; + const char hello[] = "hello"; + ostr << hello; + if(ostr.str() != hello) + { + kwsys_ios::cerr << "failed to write hello to ostr" << kwsys_ios::endl; + return 1; + } + const char world[] = "world"; + kwsys_ios::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) ) + { + kwsys_ios::cerr << "failed to write hello to ostr2" << kwsys_ios::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 unsigned int narray = sizeof(array); // 180 + kwsys_ios::stringstream strstr; + strstr.write( (char*)array, narray ); + //strstr.seekp( narray / 2 ); // set position of put pointer in mid string + if(strstr.str().size() != narray ) + { + kwsys_ios::cerr << "failed to write array to strstr" << kwsys_ios::endl; + return 1; + } + + kwsys_ios::istringstream istr(" 10 20 str "); + kwsys_stl::string s; + int x; + if(istr >> x) + { + if(x != 10) + { + kwsys_ios::cerr << "x != 10" << kwsys_ios::endl; + return 1; + } + } + else + { + kwsys_ios::cerr << "Failed to read 10 from istr" << kwsys_ios::endl; + return 1; + } + if(istr >> x) + { + if(x != 20) + { + kwsys_ios::cerr << "x != 20" << kwsys_ios::endl; + return 1; + } + } + else + { + kwsys_ios::cerr << "Failed to read 20 from istr" << kwsys_ios::endl; + return 1; + } + if(istr >> s) + { + if(s != "str") + { + kwsys_ios::cerr << "s != \"str\"" << kwsys_ios::endl; + return 1; + } + } + else + { + kwsys_ios::cerr << "Failed to read str from istr" << kwsys_ios::endl; + return 1; + } + if(istr >> s) + { + kwsys_ios::cerr << "Able to read past end of stream" << kwsys_ios::endl; + return 1; + } + else + { + // Clear the failure. + istr.clear(istr.rdstate() & ~kwsys_ios::ios::eofbit); + istr.clear(istr.rdstate() & ~kwsys_ios::ios::failbit); + } + istr.str("30"); + if(istr >> x) + { + if(x != 30) + { + kwsys_ios::cerr << "x != 30" << kwsys_ios::endl; + return 1; + } + } + else + { + kwsys_ios::cerr << "Failed to read 30 from istr" << kwsys_ios::endl; + return 1; + } + + kwsys_ios::stringstream sstr; + sstr << "40 str2"; + if(sstr >> x) + { + if(x != 40) + { + kwsys_ios::cerr << "x != 40" << kwsys_ios::endl; + return 1; + } + } + else + { + kwsys_ios::cerr << "Failed to read 40 from sstr" << kwsys_ios::endl; + return 1; + } + if(sstr >> s) + { + if(s != "str2") + { + kwsys_ios::cerr << "s != \"str2\"" << kwsys_ios::endl; + return 1; + } + } + else + { + kwsys_ios::cerr << "Failed to read str2 from sstr" << kwsys_ios::endl; + return 1; + } + + // Just try to compile this. + if(x == 12345) + { + kwsys_ios::ifstream fin("/does_not_exist", + kwsys_ios::ios::in | kwsys_ios_binary); + } + + kwsys_ios::cout << "IOS tests passed" << kwsys_ios::endl; + return 0; +} diff --git a/testProcess.c b/testProcess.c new file mode 100644 index 000000000..877002a14 --- /dev/null +++ b/testProcess.c @@ -0,0 +1,526 @@ +/*============================================================================ + 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) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Process.h.in" +#endif + +#include +#include +#include + +#if defined(_WIN32) +# include +#else +# include +#endif + +#if defined(__BORLANDC__) +# pragma warn -8060 /* possibly incorrect assignment */ +#endif + +#if defined(__BEOS__) && !defined(__ZETA__) && !defined(__HAIKU__) +/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ +# include +static inline void testProcess_usleep(unsigned int msec) +{ + snooze(msec); +} +#else +# define testProcess_usleep usleep +#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 test1(int argc, const char* argv[]) +{ + (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; +} + +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; +} + +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); +#if defined(_WIN32) + Sleep(15000); +#else + sleep(15); +#endif + fprintf(stdout, "Output after sleep on stdout from timeout test.\n"); + fprintf(stderr, "Output after sleep on stderr from timeout test.\n"); + return 0; +} + +int test4(int argc, const char* argv[]) +{ +#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); +#if defined(__clang__) + *(int*)1 = 0; /* Clang warns about 0-ptr; undefined behavior. */ +#else + *(int*)0 = 0; +#endif + fprintf(stdout, "Output after crash on stdout from crash test.\n"); + fprintf(stderr, "Output after crash on stderr from crash test.\n"); + return 0; +} + +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); + 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) +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 +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. */ +#if defined(_WIN32) + Sleep(1000); +#else + sleep(1); +#endif + fprintf(stdout, "Output on stdout after sleep.\n"); + fprintf(stderr, "Output on stderr after sleep.\n"); + fflush(stdout); + fflush(stderr); + return 0; +} + +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); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +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); +#if defined(_WIN32) + Sleep(15000); +#else + sleep(15); +#endif + return 0; +} + +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 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); + } + kwsysProcess_Execute(kp); + + if(poll) + { + pUserTimeout = &userTimeout; + } + + 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. */ +#if defined(_WIN32) + Sleep(100); +#else + testProcess_usleep(100000); +#endif + } + if(delay) + { + /* Purposely sleeping only on Win32 to let pipe fill up. */ +#if defined(_WIN32) + Sleep(100); +#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; +} + +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 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); + } + kwsysProcess_Delete(kp); + return result; +} + +int main(int argc, const char* argv[]) +{ + int n = 0; +#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 <= 8) || n == 108) && 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 108: return test8_grandchild(argc, argv); + } + fprintf(stderr, "Invalid test number %d.\n", n); + return 1; + } + else if(n >= 1 && n <= 8) + { + /* This is the parent process for a requested test number. */ + int states[8] = + { + kwsysProcess_State_Exited, + kwsysProcess_State_Exited, + kwsysProcess_State_Expired, + kwsysProcess_State_Exception, + kwsysProcess_State_Exited, + kwsysProcess_State_Expired, + kwsysProcess_State_Exited, + kwsysProcess_State_Exited + }; + int exceptions[8] = + { + kwsysProcess_Exception_None, + kwsysProcess_Exception_None, + kwsysProcess_Exception_None, + kwsysProcess_Exception_Fault, + kwsysProcess_Exception_None, + kwsysProcess_Exception_None, + kwsysProcess_Exception_None, + kwsysProcess_Exception_None + }; + int values[8] = {0, 123, 1, 1, 0, 0, 0, 0}; + int outputs[8] = {1, 1, 1, 1, 1, 0, 1, 1}; + int delays[8] = {0, 0, 0, 0, 0, 1, 0, 0}; + double timeouts[8] = {10, 10, 10, 30, 30, 10, -1, 10}; + int polls[8] = {0, 0, 0, 0, 0, 0, 1, 0}; + int repeat[8] = {2, 1, 1, 1, 1, 1, 1, 1}; + int r; + const char* cmd[4]; +#ifdef _WIN32 + char* argv0 = 0; + 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], 0, + outputs[n-1], delays[n-1], timeouts[n-1], + polls[n-1], repeat[n-1], 0); + 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 _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); + return r; + } + else + { + /* Improper usage. */ + fprintf(stdout, "Usage: %s \n", argv[0]); + return 1; + } +} diff --git a/testRegistry.cxx b/testRegistry.cxx new file mode 100644 index 000000000..7e9b0d49b --- /dev/null +++ b/testRegistry.cxx @@ -0,0 +1,109 @@ +/*============================================================================ + 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(Registry.hxx) +#include KWSYS_HEADER(ios/iostream) +#include + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Registry.hxx.in" +# include "kwsys_ios_iostream.h.in" +#endif + +#define IFT(x,res) if ( !x ) \ + { \ + res = 1; \ + kwsys_ios::cout << "Error in: " << #x << kwsys_ios::endl; \ + } +#define IFNT(x,res) if ( x ) \ + { \ + res = 1; \ + kwsys_ios::cout << "Error in: " << #x << kwsys_ios::endl; \ + } + +#define CHE(x,y,res) if ( x && strcmp(x,y) ) \ + { \ + res = 1; \ + kwsys_ios::cout << "Error, " << x << " != " << y << kwsys_ios::endl; \ + } + +int testRegistry(int, char*[]) +{ + int res = 0; + + kwsys::Registry reg; + reg.SetTopLevel("TestRegistry"); + + IFT(reg.SetValue("TestSubkey", "TestKey1", "Test Value 1"), res); + IFT(reg.SetValue("TestSubkey1", "TestKey2", "Test Value 2"), res); + IFT(reg.SetValue("TestSubkey", "TestKey3", "Test Value 3"), res); + IFT(reg.SetValue("TestSubkey2", "TestKey4", "Test Value 4"), res); + + const char *buffer; + IFT(reg.ReadValue("TestSubkey", "TestKey1", &buffer), res); + CHE(buffer, "Test Value 1", res); + IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res); + CHE(buffer, "Test Value 2", res); + IFT(reg.ReadValue("TestSubkey", "TestKey3", &buffer), res); + CHE(buffer, "Test Value 3", res); + IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res); + CHE(buffer, "Test Value 4", res); + + IFT(reg.SetValue("TestSubkey", "TestKey1", "New Test Value 1"), res); + IFT(reg.SetValue("TestSubkey1", "TestKey2", "New Test Value 2"), res); + IFT(reg.SetValue("TestSubkey", "TestKey3", "New Test Value 3"), res); + IFT(reg.SetValue("TestSubkey2", "TestKey4", "New Test Value 4"), res); + + IFT(reg.ReadValue("TestSubkey", "TestKey1", &buffer), res); + CHE(buffer, "New Test Value 1", res); + IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res); + CHE(buffer, "New Test Value 2", res); + IFT(reg.ReadValue("TestSubkey", "TestKey3", &buffer), res); + CHE(buffer, "New Test Value 3", res); + IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res); + CHE(buffer, "New Test Value 4", res); + + IFT( reg.DeleteValue("TestSubkey", "TestKey1"), res); + IFNT(reg.ReadValue( "TestSubkey", "TestKey1", &buffer), res); + IFT( reg.DeleteValue("TestSubkey1", "TestKey2"), res); + IFNT(reg.ReadValue( "TestSubkey1", "TestKey2", &buffer), res); + IFT( reg.DeleteValue("TestSubkey", "TestKey3"), res); + IFNT(reg.ReadValue( "TestSubkey", "TestKey3", &buffer), res); + IFT( reg.DeleteValue("TestSubkey2", "TestKey4"), res); + IFNT(reg.ReadValue( "TestSubkey2", "TestKey5", &buffer), res); + + const char* longStringWithNewLines = "Value with embedded CR and LF characters CR='\015' LF='\012' CRLF='\015\012'"; + IFT(reg.SetValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", longStringWithNewLines), res); + IFT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res); + CHE(buffer, longStringWithNewLines, res); + IFT(reg.DeleteValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1"), res); + IFNT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res); + + IFT(reg.SetValue("TestSubkeyWith = EqualSignChar", "TestKey = 1", "Some value"), res); + IFT(reg.ReadValue("TestSubkeyWith = EqualSignChar", "TestKey = 1", &buffer), res); + CHE(buffer, "Some value", res); + IFT(reg.DeleteValue("TestSubkeyWith = EqualSignChar", "TestKey = 1"), res); + IFNT(reg.ReadValue("TestSubkeyWith = EqualSignChar", "TestKey = 1", &buffer), res); + + if ( res ) + { + kwsys_ios::cout << "Test failed" << kwsys_ios::endl; + } + else + { + kwsys_ios::cout << "Test passed" << kwsys_ios::endl; + } + return res; +} diff --git a/testSharedForward.c.in b/testSharedForward.c.in new file mode 100644 index 000000000..ee753efa3 --- /dev/null +++ b/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/testSystemInformation.cxx b/testSystemInformation.cxx new file mode 100644 index 000000000..b3afc9de9 --- /dev/null +++ b/testSystemInformation.cxx @@ -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. +============================================================================*/ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(SystemInformation.hxx) +#include KWSYS_HEADER(ios/iostream) + + + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "SystemInformation.hxx.in" +# include "kwsys_ios_iostream.h.in" +#endif + +#define printMethod(inof, m) kwsys_ios::cout << #m << ": " \ +<< info.m() << "\n" + +#define printMethod2(inof, m, unit) kwsys_ios::cout << #m << ": " \ +<< info.m() << " " << unit << "\n" + +int testSystemInformation(int, char*[]) +{ + kwsys::SystemInformation info; + info.RunCPUCheck(); + info.RunOSCheck(); + info.RunMemoryCheck(); + printMethod(info, GetOSName); + printMethod(info, GetHostname); + 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, 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"); + + //int GetProcessorCacheXSize(long int); +// bool DoesCPUSupportFeature(long int); + return 0; +} diff --git a/testSystemTools.bin b/testSystemTools.bin new file mode 100644 index 0000000000000000000000000000000000000000..961a4043b9b2785351ab26a33cfcb1f366c1391b GIT binary patch literal 766 zcmbV~J8r`;5JX3D078KQr%G#;xrK8icPgzTq*cc{r`QAV5H3@?bYXZsLq;FVX_BRe z%g5!cJ`hlGG|ej%-%r3B^E=g0A5?{B&Opc7@6oZyO4pUdnM;@%vkIOsxNAjmXiL+d z<7 zAIM?AiVDY~%?XgU=c3&OkPg?P^8282@1&KxNx}UnZQM`N*8ME)+%M9>{YuT^22-rR A-v9sr literal 0 HcmV?d00001 diff --git a/testSystemTools.cxx b/testSystemTools.cxx new file mode 100644 index 000000000..3ac0cb399 --- /dev/null +++ b/testSystemTools.cxx @@ -0,0 +1,414 @@ +/*============================================================================ + 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) +#include KWSYS_HEADER(ios/iostream) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "SystemTools.hxx.in" +# include "kwsys_ios_iostream.h.in" +#endif + +// Include with <> instead of "" to avoid getting any in-source copy +// left on disk. +#include + +#include /* strcmp */ + +//---------------------------------------------------------------------------- +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} +}; + +bool CheckConvertToUnixSlashes(kwsys_stl::string input, + kwsys_stl::string output) +{ + kwsys_stl::string result = input; + kwsys::SystemTools::ConvertToUnixSlashes(result); + if ( result != output ) + { + kwsys_ios::cerr + << "Problem with ConvertToUnixSlashes - input: " << input.c_str() + << " output: " << result.c_str() << " expected: " << output.c_str() + << kwsys_ios::endl; + return false; + } + return true; +} + +//---------------------------------------------------------------------------- +const char* checkEscapeChars[][4] = +{ + { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2"}, + { " {} ", "{}", "#", " #{#} "}, + {0, 0, 0, 0} +}; + +bool CheckEscapeChars(kwsys_stl::string input, + const char *chars_to_escape, + char escape_char, + kwsys_stl::string output) +{ + kwsys_stl::string result = kwsys::SystemTools::EscapeChars( + input.c_str(), chars_to_escape, escape_char); + if (result != output) + { + kwsys_ios::cerr + << "Problem with CheckEscapeChars - input: " << input.c_str() + << " output: " << result.c_str() << " expected: " << output.c_str() + << kwsys_ios::endl; + return false; + } + return true; +} + +//---------------------------------------------------------------------------- +bool CheckFileOperations() +{ + bool res = true; + + if (kwsys::SystemTools::DetectFileType(TEST_SYSTEMTOOLS_BIN_FILE) != + kwsys::SystemTools::FileTypeBinary) + { + kwsys_ios::cerr + << "Problem with DetectFileType - failed to detect type of: " + << TEST_SYSTEMTOOLS_BIN_FILE << kwsys_ios::endl; + res = false; + } + + if (kwsys::SystemTools::DetectFileType(TEST_SYSTEMTOOLS_SRC_FILE) != + kwsys::SystemTools::FileTypeText) + { + kwsys_ios::cerr + << "Problem with DetectFileType - failed to detect type of: " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + if (kwsys::SystemTools::FileLength(TEST_SYSTEMTOOLS_BIN_FILE) != 766) + { + kwsys_ios::cerr + << "Problem with FileLength - incorrect length for: " + << TEST_SYSTEMTOOLS_BIN_FILE << kwsys_ios::endl; + res = false; + } + + return res; +} + +//---------------------------------------------------------------------------- +bool CheckStringOperations() +{ + bool res = true; + + kwsys_stl::string test = "mary had a little lamb."; + if (kwsys::SystemTools::CapitalizedWords(test) != "Mary Had A Little Lamb.") + { + kwsys_ios::cerr + << "Problem with CapitalizedWords " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + test = "Mary Had A Little Lamb."; + if (kwsys::SystemTools::UnCapitalizedWords(test) != + "mary had a little lamb.") + { + kwsys_ios::cerr + << "Problem with UnCapitalizedWords " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + test = "MaryHadTheLittleLamb."; + if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) != + "Mary Had The Little Lamb.") + { + kwsys_ios::cerr + << "Problem with AddSpaceBetweenCapitalizedWords " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + char * cres = + kwsys::SystemTools::AppendStrings("Mary Had A"," Little Lamb."); + if (strcmp(cres,"Mary Had A Little Lamb.")) + { + kwsys_ios::cerr + << "Problem with AppendStrings " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + delete [] cres; + + cres = + kwsys::SystemTools::AppendStrings("Mary Had"," A ","Little Lamb."); + if (strcmp(cres,"Mary Had A Little Lamb.")) + { + kwsys_ios::cerr + << "Problem with AppendStrings " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + delete [] cres; + + if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.",'a') != 3) + { + kwsys_ios::cerr + << "Problem with CountChar " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + cres = + kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.","aeiou"); + if (strcmp(cres,"Mry Hd A Lttl Lmb.")) + { + kwsys_ios::cerr + << "Problem with RemoveChars " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + delete [] cres; + + cres = + kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb."); + if (strcmp(cres,"A")) + { + kwsys_ios::cerr + << "Problem with RemoveCharsButUpperHex " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::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.")) + { + kwsys_ios::cerr + << "Problem with ReplaceChars " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + delete [] cres2; + + if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.", + "Mary ")) + { + kwsys_ios::cerr + << "Problem with StringStartsWith " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.", + " Lamb.")) + { + kwsys_ios::cerr + << "Problem with StringEndsWith " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb."); + if (strcmp(cres,"Mary Had A Little Lamb.")) + { + kwsys_ios::cerr + << "Problem with DuplicateString " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + delete [] cres; + + test = "Mary Had A Little Lamb."; + if (kwsys::SystemTools::CropString(test,13) != + "Mary ...Lamb.") + { + kwsys_ios::cerr + << "Problem with CropString " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + kwsys_stl::vector 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.") + { + kwsys_ios::cerr + << "Problem with Split " + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToWindowsOutputPath + ("L://Local Mojo/Hex Power Pack/Iffy Voodoo") != + "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") + { + kwsys_ios::cerr + << "Problem with ConvertToWindowsOutputPath " + << kwsys_ios::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToWindowsOutputPath + ("//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") != + "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") + { + kwsys_ios::cerr + << "Problem with ConvertToWindowsOutputPath " + << kwsys_ios::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToUnixOutputPath + ("//Local Mojo/Hex Power Pack/Iffy Voodoo") != + "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo") + { + kwsys_ios::cerr + << "Problem with ConvertToUnixOutputPath " + << kwsys_ios::endl; + res = false; + } + + int targc; + char **targv; + kwsys::SystemTools::ConvertWindowsCommandLineToUnixArguments + ("\"Local Mojo\\Voodoo.asp\" -CastHex \"D:\\My Secret Mojo\\Voodoo.mp3\"", &targc, &targv); + if (targc != 4 || strcmp(targv[1],"Local Mojo\\Voodoo.asp") || + strcmp(targv[2],"-CastHex") || + strcmp(targv[3],"D:\\My Secret Mojo\\Voodoo.mp3")) + { + kwsys_ios::cerr + << "Problem with ConvertWindowsCommandLineToUnixArguments" + << TEST_SYSTEMTOOLS_SRC_FILE << kwsys_ios::endl; + res = false; + } + for (;targc >=0; --targc) + { + delete [] targv[targc]; + } + delete [] targv; + + return res; +} + +//---------------------------------------------------------------------------- + +bool CheckPutEnv(const char* env, const char* name, const char* value) +{ + if(!kwsys::SystemTools::PutEnv(env)) + { + kwsys_ios::cerr << "PutEnv(\"" << env + << "\") failed!" << kwsys_ios::endl; + return false; + } + const char* v = kwsys::SystemTools::GetEnv(name); + v = v? v : "(null)"; + if(strcmp(v, value) != 0) + { + kwsys_ios::cerr << "GetEnv(\"" << name << "\") returned \"" + << v << "\", not \"" << value << "\"!" << kwsys_ios::endl; + return false; + } + return true; +} + +bool CheckUnPutEnv(const char* env, const char* name) +{ + if(!kwsys::SystemTools::UnPutEnv(env)) + { + kwsys_ios::cerr << "UnPutEnv(\"" << env << "\") failed!" + << kwsys_ios::endl; + return false; + } + if(const char* v = kwsys::SystemTools::GetEnv(name)) + { + kwsys_ios::cerr << "GetEnv(\"" << name << "\") returned \"" + << v << "\", not (null)!" << kwsys_ios::endl; + return false; + } + return true; +} + +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; +} + +//---------------------------------------------------------------------------- +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 ~ + kwsys_stl::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(); + + return res ? 0 : 1; +} diff --git a/testSystemTools.h.in b/testSystemTools.h.in new file mode 100644 index 000000000..4b94bb6af --- /dev/null +++ b/testSystemTools.h.in @@ -0,0 +1,20 @@ +/*============================================================================ + 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_BIN_FILE "@TEST_SYSTEMTOOLS_BIN_FILE@" +#define TEST_SYSTEMTOOLS_SRC_FILE "@TEST_SYSTEMTOOLS_SRC_FILE@" + +#endif diff --git a/testTerminal.c b/testTerminal.c new file mode 100644 index 000000000..0d2d7a77b --- /dev/null +++ b/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; +}