Changes to isolate API Test option files and use fetchcontent (#2880)

This commit is contained in:
Allen Byrne
2023-05-03 11:45:16 -05:00
committed by GitHub
parent f8a1b3ceec
commit 571990d5c4
113 changed files with 89 additions and 36608 deletions
+11
View File
@@ -49,6 +49,10 @@ set (HDF5_MINGW_STATIC_GCC_LIBS ON CACHE BOOL "Statically link libgcc/libstdc++"
set (HDF5_ALLOW_EXTERNAL_SUPPORT "TGZ" CACHE STRING "Allow External Library Building (NO GIT TGZ)" FORCE)
set_property (CACHE HDF5_ALLOW_EXTERNAL_SUPPORT PROPERTY STRINGS NO GIT TGZ)
########################
# compression options
########################
set (ZLIB_PACKAGE_NAME "zlib" CACHE STRING "Name of ZLIB package" FORCE)
set (ZLIB_TGZ_NAME "ZLib.tar.gz" CACHE STRING "Use HDF5_ZLib from compressed file" FORCE)
set (ZLIB_TGZ_ORIGPATH "https://github.com/madler/zlib/releases/download/v1.2.13" CACHE STRING "Use ZLIB from original location" FORCE)
@@ -61,6 +65,13 @@ set (LIBAEC_TGZ_ORIGPATH "https://github.com/MathisRosenhauer/libaec/releases/do
set (LIBAEC_TGZ_ORIGNAME "libaec-v1.0.6.tar.gz" CACHE STRING "Use LIBAEC from original compressed file" FORCE)
set (LIBAEC_USE_LOCALCONTENT OFF CACHE BOOL "Use local file for LIBAEC FetchContent" FORCE)
########################
# API test options
########################
set (KWSYS_TGZ_ORIGPATH "https://gitlab.kitware.com/utils/kwsys/-/archive/master/kwsys-master.tar.gz" CACHE STRING "Use KWSYS from original location" FORCE)
set (KWSYS_TGZ_ORIGNAME "kwsys-master.tar.gz" CACHE STRING "Use KWSYS from original compressed file" FORCE)
set (KWSYS_USE_LOCALCONTENT OFF CACHE BOOL "Use local file for KWSYS FetchContent" FORCE)
########################
# filter plugin options
########################
+1 -1
View File
@@ -23,7 +23,7 @@ documents cover a mix of tasks, concepts, and reference, to help a specific
\par Versions
Version-specific documentation (see the version in the title area) can be found
here:
- HDF5 <code>develop</code> branch (this site)
- <a href="https://docs.hdfgroup.org/hdf5/develop/index.html">HDF5 <code>develop</code> branch (this site)
- <a href="https://docs.hdfgroup.org/hdf5/v1_14/index.html">HDF5 1.14.x</a>
- <a href="https://docs.hdfgroup.org/hdf5/v1_12/index.html">HDF5 1.12.x</a>
- <a href="https://docs.hdfgroup.org/hdf5/v1_10/index.html">HDF5 1.10.x</a>
-37
View File
@@ -1,37 +0,0 @@
set(ASAN_FLAG "-fsanitize=address")
set(ASAN_C_FLAGS "-O1 -g ${ASAN_FLAG} -fsanitize-address-use-after-scope -fno-omit-frame-pointer -fno-optimize-sibling-calls")
set(ASAN_CXX_FLAGS ${ASAN_C_FLAGS})
get_property(ASAN_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
foreach(lang ${ASAN_LANGUAGES})
set(ASAN_${lang}_LANG_ENABLED 1)
endforeach()
if(ASAN_C_LANG_ENABLED)
include(CheckCCompilerFlag)
set(CMAKE_REQUIRED_LINK_OPTIONS ${ASAN_FLAG})
check_c_compiler_flag(${ASAN_FLAG} ASAN_C_FLAG_SUPPORTED)
if(NOT ASAN_C_FLAG_SUPPORTED)
message(STATUS "Asan flags are not supported by the C compiler.")
else()
if(NOT CMAKE_C_FLAGS_ASAN)
set(CMAKE_C_FLAGS_ASAN ${ASAN_C_FLAGS} CACHE STRING "Flags used by the C compiler during ASAN builds." FORCE)
endif()
endif()
unset(CMAKE_REQUIRED_LINK_OPTIONS)
endif()
if(ASAN_CXX_LANG_ENABLED)
include(CheckCXXCompilerFlag)
set(CMAKE_REQUIRED_LINK_OPTIONS ${ASAN_FLAG})
check_cxx_compiler_flag(${ASAN_FLAG} ASAN_CXX_FLAG_SUPPORTED)
if(NOT ASAN_CXX_FLAG_SUPPORTED)
message(STATUS "Asan flags are not supported by the CXX compiler.")
else()
if(NOT CMAKE_CXX_FLAGS_ASAN)
set(CMAKE_CXX_FLAGS_ASAN ${ASAN_CXX_FLAGS} CACHE STRING "Flags used by the CXX compiler during ASAN builds." FORCE)
endif()
endif()
unset(CMAKE_REQUIRED_LINK_OPTIONS)
endif()
-37
View File
@@ -1,37 +0,0 @@
set(UBSAN_FLAG "-fsanitize=undefined")
set(UBSAN_C_FLAGS "-O1 -g ${UBSAN_FLAG} -fno-omit-frame-pointer")
set(UBSAN_CXX_FLAGS ${UBSAN_C_FLAGS})
get_property(UBSAN_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
foreach(lang ${UBSAN_LANGUAGES})
set(UBSAN_${lang}_LANG_ENABLED 1)
endforeach()
if(UBSAN_C_LANG_ENABLED)
include(CheckCCompilerFlag)
set(CMAKE_REQUIRED_LINK_OPTIONS ${UBSAN_FLAG})
check_c_compiler_flag(${UBSAN_FLAG} UBSAN_C_FLAG_SUPPORTED)
if(NOT UBSAN_C_FLAG_SUPPORTED)
message(STATUS "Ubsan flags are not supported by the C compiler.")
else()
if(NOT CMAKE_C_FLAGS_UBSAN)
set(CMAKE_C_FLAGS_UBSAN ${UBSAN_C_FLAGS} CACHE STRING "Flags used by the C compiler during UBSAN builds." FORCE)
endif()
endif()
unset(CMAKE_REQUIRED_LINK_OPTIONS)
endif()
if(UBSAN_CXX_LANG_ENABLED)
include(CheckCXXCompilerFlag)
set(CMAKE_REQUIRED_LINK_OPTIONS ${UBSAN_FLAG})
check_cxx_compiler_flag(${UBSAN_FLAG} UBSAN_CXX_FLAG_SUPPORTED)
if(NOT UBSAN_CXX_FLAG_SUPPORTED)
message(STATUS "Ubsan flags are not supported by the CXX compiler.")
else()
if(NOT CMAKE_CXX_FLAGS_UBSAN)
set(CMAKE_CXX_FLAGS_UBSAN ${UBSAN_CXX_FLAGS} CACHE STRING "Flags used by the CXX compiler during UBSAN builds." FORCE)
endif()
endif()
unset(CMAKE_REQUIRED_LINK_OPTIONS)
endif()
+21 -17
View File
@@ -9,26 +9,12 @@
# help@hdfgroup.org.
#
#------------------------------------------------------------------------------
# Set module path
#------------------------------------------------------------------------------
set(HDF5_TEST_API_CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${HDF5_TEST_API_CMAKE_MODULE_PATH})
# TODO: probably not necessary
#------------------------------------------------------------------------------
# Setup CMake Environment
#------------------------------------------------------------------------------
if (WIN32)
message("The HDF5 API test suite is currently not supported on this platform." FATAL_ERROR)
endif ()
cmake_minimum_required (VERSION 3.18)
project (HDF5_TEST_API C)
#------------------------------------------------------------------------------
# Setup testing configuration file
#------------------------------------------------------------------------------
if (HDF5_TEST_PARALLEL)
set (HDF5_TEST_API_HAVE_PARALLEL 1)
endif ()
if (HDF5_TEST_API_ENABLE_ASYNC)
set (H5_API_TEST_HAVE_ASYNC 1)
endif ()
@@ -46,9 +32,27 @@ if (HDF5_TEST_API_ENABLE_DRIVER)
endif ()
#------------------------------------------------------------------------------
# Setup for API tests
# Define for API tests
#------------------------------------------------------------------------------
set (HDF5_API_TESTS
attribute
dataset
datatype
file
group
link
misc
object
)
if (HDF5_TEST_API_ENABLE_ASYNC)
set (HDF5_API_TESTS
${HDF5_API_TESTS}
async
)
endif ()
# Ported HDF5 tests
set (HDF5_API_TESTS_EXTRA
testhdf5
+27 -10
View File
@@ -1,17 +1,34 @@
cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR)
cmake_minimum_required (VERSION 3.18)
project(H5_API_TEST_DRIVER CXX)
include(CheckAsan)
include(CheckUbsan)
if (NOT KWSYS_USE_LOCALCONTENT)
set (KWSYS_URL ${KWSYS_TGZ_ORIGPATH}/${KWSYS_TGZ_ORIGNAME})
else ()
set (KWSYS_URL ${TGZPATH}/${KWSYS_TGZ_ORIGNAME})
endif ()
# Only tgz files
FetchContent_Declare (KWSYS
URL ${KWSYS_URL}
URL_HASH ""
)
FetchContent_GetProperties(KWSYS)
if(NOT kwsys_POPULATED)
FetchContent_Populate(KWSYS)
set(CMAKE_CXX_STANDARD 11)
# Copy an additional/replacement files into the populated source
#file(COPY ${HDF_RESOURCES_DIR}/KWSYS/CMakeLists.txt DESTINATION ${hdf5_kwsys_SOURCE_DIR})
set(KWSYS_NAMESPACE h5_api_test_sys)
set(KWSYS_USE_SystemTools 1)
set(KWSYS_USE_Process 1)
set(KWSYS_USE_RegularExpression 1)
add_subdirectory(kwsys)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/kwsys)
set(CMAKE_CXX_STANDARD 11)
set(KWSYS_NAMESPACE h5_api_test_sys)
set(KWSYS_USE_SystemTools 1)
set(KWSYS_USE_Process 1)
set(KWSYS_USE_RegularExpression 1)
add_subdirectory(${hdf5_kwsysb_SOURCE_DIR} ${hdf5_kwsys_BINARY_DIR})
endif()
include_directories(${hdf5_kwsys_BINARY_DIR})
add_executable(h5_api_test_driver h5_api_test_driver.cxx)
target_link_libraries(h5_api_test_driver h5_api_test_sys)
-22
View File
@@ -1,22 +0,0 @@
---
# This configuration requires clang-format version 6.0 exactly.
BasedOnStyle: Mozilla
AlignOperands: false
AllowShortFunctionsOnASingleLine: InlineOnly
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterEnum: true
AfterFunction: true
AfterStruct: true
AfterUnion: true
BreakBeforeBraces: Custom
ColumnLimit: 79
IndentPPDirectives: AfterHash
SortUsingDeclarations: false
SpaceAfterTemplateKeyword: true
Standard: Cpp03
...
-2
View File
@@ -1,2 +0,0 @@
[hooks "chain"]
pre-commit = GitSetup/pre-commit
-225
View File
@@ -1,225 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Base64.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
#if 0
# include "Base64.h.in"
#endif
static const unsigned char kwsysBase64EncodeTable[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static const unsigned char kwsysBase64DecodeTable[256] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/*------------------------------------*/
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static unsigned char kwsysBase64EncodeChar(int c)
{
return kwsysBase64EncodeTable[(unsigned char)c];
}
static unsigned char kwsysBase64DecodeChar(unsigned char c)
{
return kwsysBase64DecodeTable[c];
}
/* Encode 3 bytes into a 4 byte string. */
void kwsysBase64_Encode3(const unsigned char* src, unsigned char* dest)
{
dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
dest[1] =
kwsysBase64EncodeChar(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0F));
dest[2] =
kwsysBase64EncodeChar(((src[1] << 2) & 0x3C) | ((src[2] >> 6) & 0x03));
dest[3] = kwsysBase64EncodeChar(src[2] & 0x3F);
}
/* Encode 2 bytes into a 4 byte string. */
void kwsysBase64_Encode2(const unsigned char* src, unsigned char* dest)
{
dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
dest[1] =
kwsysBase64EncodeChar(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0F));
dest[2] = kwsysBase64EncodeChar(((src[1] << 2) & 0x3C));
dest[3] = '=';
}
/* Encode 1 bytes into a 4 byte string. */
void kwsysBase64_Encode1(const unsigned char* src, unsigned char* dest)
{
dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F);
dest[1] = kwsysBase64EncodeChar(((src[0] << 4) & 0x30));
dest[2] = '=';
dest[3] = '=';
}
/* Encode 'length' bytes from the input buffer and store the
encoded stream into the output buffer. Return the length of the encoded
buffer (output). Note that the output buffer must be allocated by the caller
(length * 1.5 should be a safe estimate). If 'mark_end' is true than an
extra set of 4 bytes is added to the end of the stream if the input is a
multiple of 3 bytes. These bytes are invalid chars and therefore they will
stop the decoder thus enabling the caller to decode a stream without
actually knowing how much data to expect (if the input is not a multiple of
3 bytes then the extra padding needed to complete the encode 4 bytes will
stop the decoding anyway). */
size_t kwsysBase64_Encode(const unsigned char* input, size_t length,
unsigned char* output, int mark_end)
{
const unsigned char* ptr = input;
const unsigned char* end = input + length;
unsigned char* optr = output;
/* Encode complete triplet */
while ((end - ptr) >= 3) {
kwsysBase64_Encode3(ptr, optr);
ptr += 3;
optr += 4;
}
/* Encodes a 2-byte ending into 3 bytes and 1 pad byte and writes. */
if (end - ptr == 2) {
kwsysBase64_Encode2(ptr, optr);
optr += 4;
}
/* Encodes a 1-byte ending into 2 bytes and 2 pad bytes */
else if (end - ptr == 1) {
kwsysBase64_Encode1(ptr, optr);
optr += 4;
}
/* Do we need to mark the end */
else if (mark_end) {
optr[0] = optr[1] = optr[2] = optr[3] = '=';
optr += 4;
}
return (size_t)(optr - output);
}
/* Decode 4 bytes into a 3 byte string. */
int kwsysBase64_Decode3(const unsigned char* src, unsigned char* dest)
{
unsigned char d0, d1, d2, d3;
d0 = kwsysBase64DecodeChar(src[0]);
d1 = kwsysBase64DecodeChar(src[1]);
d2 = kwsysBase64DecodeChar(src[2]);
d3 = kwsysBase64DecodeChar(src[3]);
/* Make sure all characters were valid */
if (d0 == 0xFF || d1 == 0xFF || d2 == 0xFF || d3 == 0xFF) {
return 0;
}
/* Decode the 3 bytes */
dest[0] = (unsigned char)(((d0 << 2) & 0xFC) | ((d1 >> 4) & 0x03));
dest[1] = (unsigned char)(((d1 << 4) & 0xF0) | ((d2 >> 2) & 0x0F));
dest[2] = (unsigned char)(((d2 << 6) & 0xC0) | ((d3 >> 0) & 0x3F));
/* Return the number of bytes actually decoded */
if (src[2] == '=') {
return 1;
}
if (src[3] == '=') {
return 2;
}
return 3;
}
/* Decode bytes from the input buffer and store the decoded stream
into the output buffer until 'length' bytes have been decoded. Return the
real length of the decoded stream (which should be equal to 'length'). Note
that the output buffer must be allocated by the caller. If
'max_input_length' is not null, then it specifies the number of encoded
bytes that should be at most read from the input buffer. In that case the
'length' parameter is ignored. This enables the caller to decode a stream
without actually knowing how much decoded data to expect (of course, the
buffer must be large enough). */
size_t kwsysBase64_Decode(const unsigned char* input, size_t length,
unsigned char* output, size_t max_input_length)
{
const unsigned char* ptr = input;
unsigned char* optr = output;
/* Decode complete triplet */
if (max_input_length) {
const unsigned char* end = input + max_input_length;
while (ptr < end) {
int len = kwsysBase64_Decode3(ptr, optr);
optr += len;
if (len < 3) {
return (size_t)(optr - output);
}
ptr += 4;
}
} else {
unsigned char* oend = output + length;
while ((oend - optr) >= 3) {
int len = kwsysBase64_Decode3(ptr, optr);
optr += len;
if (len < 3) {
return (size_t)(optr - output);
}
ptr += 4;
}
/* Decode the last triplet */
if (oend - optr == 2) {
unsigned char temp[3];
int len = kwsysBase64_Decode3(ptr, temp);
if (len >= 2) {
optr[0] = temp[0];
optr[1] = temp[1];
optr += 2;
} else if (len > 0) {
optr[0] = temp[0];
optr += 1;
}
} else if (oend - optr == 1) {
unsigned char temp[3];
int len = kwsysBase64_Decode3(ptr, temp);
if (len > 0) {
optr[0] = temp[0];
optr += 1;
}
}
}
return (size_t)(optr - output);
}
-110
View File
@@ -1,110 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Base64_h
#define @KWSYS_NAMESPACE@_Base64_h
#include <@KWSYS_NAMESPACE@/Configure.h>
#include <stddef.h> /* size_t */
/* Redefine all public interface symbol names to be in the proper
namespace. These macros are used internally to kwsys only, and are
not visible to user code. Use kwsysHeaderDump.pl to reproduce
these macros after making changes to the interface. */
#if !defined(KWSYS_NAMESPACE)
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsysBase64 kwsys_ns(Base64)
# define kwsysBase64_Decode kwsys_ns(Base64_Decode)
# define kwsysBase64_Decode3 kwsys_ns(Base64_Decode3)
# define kwsysBase64_Encode kwsys_ns(Base64_Encode)
# define kwsysBase64_Encode1 kwsys_ns(Base64_Encode1)
# define kwsysBase64_Encode2 kwsys_ns(Base64_Encode2)
# define kwsysBase64_Encode3 kwsys_ns(Base64_Encode3)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/**
* Encode 3 bytes into a 4 byte string.
*/
kwsysEXPORT void kwsysBase64_Encode3(const unsigned char* src,
unsigned char* dest);
/**
* Encode 2 bytes into a 4 byte string.
*/
kwsysEXPORT void kwsysBase64_Encode2(const unsigned char* src,
unsigned char* dest);
/**
* Encode 1 bytes into a 4 byte string.
*/
kwsysEXPORT void kwsysBase64_Encode1(const unsigned char* src,
unsigned char* dest);
/**
* Encode 'length' bytes from the input buffer and store the encoded
* stream into the output buffer. Return the length of the encoded
* buffer (output). Note that the output buffer must be allocated by
* the caller (length * 1.5 should be a safe estimate). If 'mark_end'
* is true than an extra set of 4 bytes is added to the end of the
* stream if the input is a multiple of 3 bytes. These bytes are
* invalid chars and therefore they will stop the decoder thus
* enabling the caller to decode a stream without actually knowing how
* much data to expect (if the input is not a multiple of 3 bytes then
* the extra padding needed to complete the encode 4 bytes will stop
* the decoding anyway).
*/
kwsysEXPORT size_t kwsysBase64_Encode(const unsigned char* input,
size_t length, unsigned char* output,
int mark_end);
/**
* Decode 4 bytes into a 3 byte string. Returns the number of bytes
* actually decoded.
*/
kwsysEXPORT int kwsysBase64_Decode3(const unsigned char* src,
unsigned char* dest);
/**
* Decode bytes from the input buffer and store the decoded stream
* into the output buffer until 'length' bytes have been decoded.
* Return the real length of the decoded stream (which should be equal
* to 'length'). Note that the output buffer must be allocated by the
* caller. If 'max_input_length' is not null, then it specifies the
* number of encoded bytes that should be at most read from the input
* buffer. In that case the 'length' parameter is ignored. This
* enables the caller to decode a stream without actually knowing how
* much decoded data to expect (of course, the buffer must be large
* enough).
*/
kwsysEXPORT size_t kwsysBase64_Decode(const unsigned char* input,
size_t length, unsigned char* output,
size_t max_input_length);
#if defined(__cplusplus)
} /* extern "C" */
#endif
/* If we are building a kwsys .c or .cxx file, let it use these macros.
Otherwise, undefine them to keep the namespace clean. */
#if !defined(KWSYS_NAMESPACE)
# undef kwsys_ns
# undef kwsysEXPORT
# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# undef kwsysBase64
# undef kwsysBase64_Decode
# undef kwsysBase64_Decode3
# undef kwsysBase64_Encode
# undef kwsysBase64_Encode1
# undef kwsysBase64_Encode2
# undef kwsysBase64_Encode3
# endif
#endif
#endif
-1260
View File
@@ -1,1260 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
# The Kitware System Library is intended to be included in other
# projects. It is completely configurable in that the library's
# namespace can be configured and the components that are included can
# be selected invididually.
# Typical usage is to import the kwsys directory tree into a
# subdirectory under a parent project and enable the classes that will
# be used. All classes are disabled by default. The CMake listfile
# above this one configures the library as follows:
#
# SET(KWSYS_NAMESPACE foosys)
# SET(KWSYS_USE_Directory 1) # Enable Directory class.
# SUBDIRS(kwsys)
#
# Optional settings are as follows:
#
# KWSYS_HEADER_ROOT = The directory into which to generate the kwsys headers.
# A directory called "${KWSYS_NAMESPACE}" will be
# created under this root directory to hold the files.
# KWSYS_SPLIT_OBJECTS_FROM_INTERFACE
# = Instead of creating a single ${KWSYS_NAMESPACE} library
# target, create three separate targets:
# ${KWSYS_NAMESPACE}
# - An INTERFACE library only containing usage
# requirements.
# ${KWSYS_NAMESPACE}_objects
# - An OBJECT library for the built kwsys objects.
# Note: This is omitted from the install rules
# ${KWSYS_NAMESPACE}_private
# - An INTERFACE library combining both that is
# appropriate for use with PRIVATE linking in
# target_link_libraries. Because of how interface
# properties propagate, this target is not suitable
# for use with PUBLIC or INTERFACE linking.
# KWSYS_ALIAS_TARGET = The name of an alias target to create to the actual target.
#
# Example:
#
# SET(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR})
# INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR})
#
# KWSYS_CXX_STANDARD = A value for CMAKE_CXX_STANDARD within KWSys.
# Set to empty string to use no default value.
# KWSYS_CXX_COMPILE_FEATURES = target_compile_features arguments for KWSys.
#
# Optional settings to setup install rules are as follows:
#
# KWSYS_INSTALL_BIN_DIR = The installation target directories into
# KWSYS_INSTALL_LIB_DIR which the libraries and headers from
# KWSYS_INSTALL_INCLUDE_DIR kwsys should be installed by a "make install".
# The values should be specified relative to
# the installation prefix and NOT start with '/'.
# KWSYS_INSTALL_DOC_DIR = The installation target directory for documentation
# such as copyright information.
#
# KWSYS_INSTALL_COMPONENT_NAME_RUNTIME = Name of runtime and development
# KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT installation components.
# If not given the install rules
# will not be in any component.
#
# KWSYS_INSTALL_EXPORT_NAME = The EXPORT option value for install(TARGETS) calls.
#
# Example:
#
# SET(KWSYS_INSTALL_BIN_DIR bin)
# SET(KWSYS_INSTALL_LIB_DIR lib)
# SET(KWSYS_INSTALL_INCLUDE_DIR include)
# SET(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime)
# SET(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development)
# Once configured, kwsys should be used as follows from C or C++ code:
#
# #include <foosys/Directory.hxx>
# ...
# foosys::Directory directory;
#
# NOTE: This library is intended for internal use by Kitware-driven
# projects. In order to keep it simple no attempt will be made to
# maintain backward compatibility when changes are made to KWSys.
# When an incompatible change is made Kitware's projects that use
# KWSys will be fixed, but no notification will necessarily be sent to
# any outside mailing list and no documentation of the change will be
# written.
CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR)
FOREACH(p
CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature.
CMP0063 # CMake 3.3, Honor visibility properties for all target types.
CMP0067 # CMake 3.8, Honor language standard in try_compile source-file signature.
CMP0069 # CMake 3.9, INTERPROCEDURAL_OPTIMIZATION is enforced when enabled.
)
IF(POLICY ${p})
CMAKE_POLICY(SET ${p} NEW)
ENDIF()
ENDFOREACH()
#-----------------------------------------------------------------------------
# If a namespace is not specified, use "kwsys" and enable testing.
# This should be the case only when kwsys is not included inside
# another project and is being tested.
IF(NOT KWSYS_NAMESPACE)
SET(KWSYS_NAMESPACE "kwsys")
SET(KWSYS_STANDALONE 1)
ENDIF()
#-----------------------------------------------------------------------------
# The project name is that of the specified namespace.
PROJECT(${KWSYS_NAMESPACE})
# Tell CMake how to follow dependencies of sources in this directory.
SET_PROPERTY(DIRECTORY
PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
"KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>"
)
if(KWSYS_CXX_STANDARD)
set(CMAKE_CXX_STANDARD "${KWSYS_CXX_STANDARD}")
elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"
AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU"
)
set(CMAKE_CXX_STANDARD 14)
else()
set(CMAKE_CXX_STANDARD 11)
endif()
endif()
# Select library components.
IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
SET(KWSYS_ENABLE_C 1)
# Enable all components.
SET(KWSYS_USE_Base64 1)
SET(KWSYS_USE_Directory 1)
SET(KWSYS_USE_DynamicLoader 1)
SET(KWSYS_USE_Encoding 1)
SET(KWSYS_USE_Glob 1)
SET(KWSYS_USE_MD5 1)
SET(KWSYS_USE_Process 1)
SET(KWSYS_USE_RegularExpression 1)
SET(KWSYS_USE_System 1)
SET(KWSYS_USE_SystemTools 1)
SET(KWSYS_USE_CommandLineArguments 1)
SET(KWSYS_USE_Terminal 1)
SET(KWSYS_USE_IOStream 1)
SET(KWSYS_USE_FStream 1)
SET(KWSYS_USE_String 1)
SET(KWSYS_USE_SystemInformation 1)
SET(KWSYS_USE_ConsoleBuf 1)
ENDIF()
# Enforce component dependencies.
IF(KWSYS_USE_SystemTools)
SET(KWSYS_USE_Directory 1)
SET(KWSYS_USE_FStream 1)
SET(KWSYS_USE_Encoding 1)
ENDIF()
IF(KWSYS_USE_Glob)
SET(KWSYS_USE_Directory 1)
SET(KWSYS_USE_SystemTools 1)
SET(KWSYS_USE_RegularExpression 1)
SET(KWSYS_USE_FStream 1)
SET(KWSYS_USE_Encoding 1)
ENDIF()
IF(KWSYS_USE_Process)
SET(KWSYS_USE_System 1)
SET(KWSYS_USE_Encoding 1)
ENDIF()
IF(KWSYS_USE_SystemInformation)
SET(KWSYS_USE_Process 1)
ENDIF()
IF(KWSYS_USE_System)
SET(KWSYS_USE_Encoding 1)
ENDIF()
IF(KWSYS_USE_Directory)
SET(KWSYS_USE_Encoding 1)
ENDIF()
IF(KWSYS_USE_DynamicLoader)
SET(KWSYS_USE_Encoding 1)
ENDIF()
IF(KWSYS_USE_FStream)
SET(KWSYS_USE_Encoding 1)
ENDIF()
IF(KWSYS_USE_ConsoleBuf)
SET(KWSYS_USE_Encoding 1)
ENDIF()
# Specify default 8 bit encoding for Windows
IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE)
SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP)
ENDIF()
# Enable testing if building standalone.
IF(KWSYS_STANDALONE)
INCLUDE(Dart)
MARK_AS_ADVANCED(BUILD_TESTING DART_ROOT TCL_TCLSH)
IF(BUILD_TESTING)
ENABLE_TESTING()
ENDIF()
ENDIF()
# Choose default shared/static build if not specified.
IF(NOT DEFINED KWSYS_BUILD_SHARED)
SET(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS})
ENDIF()
# Include helper macros.
INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake)
INCLUDE(CheckTypeSize)
# Do full dependency headers.
INCLUDE_REGULAR_EXPRESSION("^.*$")
# Use new KWSYS_INSTALL_*_DIR variable names to control installation.
# Take defaults from the old names. Note that there was no old name
# for the bin dir, so we take the old lib dir name so DLLs will be
# installed in a compatible way for old code.
IF(NOT KWSYS_INSTALL_INCLUDE_DIR)
STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR
"${KWSYS_HEADER_INSTALL_DIR}")
ENDIF()
IF(NOT KWSYS_INSTALL_LIB_DIR)
STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR
"${KWSYS_LIBRARY_INSTALL_DIR}")
ENDIF()
IF(NOT KWSYS_INSTALL_BIN_DIR)
STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR
"${KWSYS_LIBRARY_INSTALL_DIR}")
ENDIF()
# Setup header install rules.
SET(KWSYS_INSTALL_INCLUDE_OPTIONS)
IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
SET(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS}
COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
)
ENDIF()
# Setup library install rules.
SET(KWSYS_INSTALL_LIBRARY_RULE)
SET(KWSYS_INSTALL_NAMELINK_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} NAMELINK_SKIP
)
# 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()
IF(KWSYS_BUILD_SHARED)
SET(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE}
LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_ONLY
)
# Assign the namelink to the development component.
IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
SET(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE}
COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
)
ENDIF()
ENDIF()
# Install the archive to the lib directory.
SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR}
)
# Assign the archive to the development component.
IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT)
SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT}
)
ENDIF()
ENDIF()
IF(KWSYS_INSTALL_BIN_DIR)
# Install the runtime library to the bin directory.
SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR}
)
# Assign the runtime library to the runtime component.
IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE}
COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
)
ENDIF()
ENDIF()
# Do not support old KWSYS_*a_INSTALL_DIR variable names.
SET(KWSYS_HEADER_INSTALL_DIR)
SET(KWSYS_LIBRARY_INSTALL_DIR)
# Generated source files will need this header.
STRING(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}"
KWSYS_IN_SOURCE_BUILD)
IF(NOT KWSYS_IN_SOURCE_BUILD)
CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsysPrivate.h
${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE)
ENDIF()
# Select plugin module file name convention.
IF(NOT KWSYS_DynamicLoader_PREFIX)
SET(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX})
ENDIF()
IF(NOT KWSYS_DynamicLoader_SUFFIX)
SET(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX})
ENDIF()
#-----------------------------------------------------------------------------
# We require ANSI support from the C compiler. Add any needed flags.
IF(CMAKE_ANSI_CFLAGS)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}")
ENDIF()
#-----------------------------------------------------------------------------
# Adjust compiler flags for some platforms.
IF(NOT CMAKE_COMPILER_IS_GNUCXX)
IF(CMAKE_SYSTEM MATCHES "OSF1-V.*")
STRING(REGEX MATCH "-timplicit_local"
KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}")
STRING(REGEX MATCH "-no_implicit_include"
KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}")
IF(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local")
ENDIF()
IF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include")
ENDIF()
ENDIF()
IF(CMAKE_SYSTEM MATCHES "HP-UX")
SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p")
IF(CMAKE_CXX_COMPILER_ID MATCHES "HP")
# it is known that version 3.85 fails and 6.25 works without these flags
IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4)
# use new C++ library and improved template support
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98")
ENDIF()
ENDIF()
ENDIF()
ENDIF()
IF(KWSYS_STANDALONE)
IF(CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
ELSE()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4")
ENDIF()
ENDIF()
ENDIF()
#-----------------------------------------------------------------------------
# Configure the standard library header wrappers based on compiler's
# capabilities and parent project's request. Enforce 0/1 as only
# possible values for configuration into Configure.hxx.
# Check existence and uniqueness of long long and __int64.
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_LONG_LONG
"Checking whether C++ compiler has 'long long'" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS___INT64
"Checking whether C++ compiler has '__int64'" DIRECT)
IF(KWSYS_CXX_HAS___INT64)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_AND___INT64
"Checking whether long and __int64 are the same type" DIRECT)
IF(KWSYS_CXX_HAS_LONG_LONG)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_LONG_AND___INT64
"Checking whether long long and __int64 are the same type" DIRECT)
ENDIF()
ENDIF()
# Enable the "long long" type if it is available. It is standard in
# C99 and C++03 but not in earlier standards.
IF(KWSYS_CXX_HAS_LONG_LONG)
SET(KWSYS_USE_LONG_LONG 1)
ELSE()
SET(KWSYS_USE_LONG_LONG 0)
ENDIF()
# Enable the "__int64" type if it is available and unique. It is not
# standard.
SET(KWSYS_USE___INT64 0)
IF(KWSYS_CXX_HAS___INT64)
IF(NOT KWSYS_CXX_SAME_LONG_AND___INT64)
IF(NOT KWSYS_CXX_SAME_LONG_LONG_AND___INT64)
SET(KWSYS_USE___INT64 1)
ENDIF()
ENDIF()
ENDIF()
IF(KWSYS_USE_Encoding)
# Look for type size helper macros.
KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING
"Checking whether wstring is available" DIRECT)
ENDIF()
IF(KWSYS_USE_IOStream)
# Determine whether iostreams support long long.
IF(KWSYS_CXX_HAS_LONG_LONG)
KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG
"Checking if istream supports long long" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG
"Checking if ostream supports long long" DIRECT)
ELSE()
SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0)
SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0)
ENDIF()
IF(KWSYS_CXX_HAS___INT64)
KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM___INT64
"Checking if istream supports __int64" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM___INT64
"Checking if ostream supports __int64" DIRECT)
ELSE()
SET(KWSYS_IOS_HAS_ISTREAM___INT64 0)
SET(KWSYS_IOS_HAS_OSTREAM___INT64 0)
ENDIF()
ENDIF()
IF(KWSYS_NAMESPACE MATCHES "^kwsys$")
SET(KWSYS_NAME_IS_KWSYS 1)
ELSE()
SET(KWSYS_NAME_IS_KWSYS 0)
ENDIF()
IF(KWSYS_BUILD_SHARED)
SET(KWSYS_BUILD_SHARED 1)
SET(KWSYS_LIBRARY_TYPE SHARED)
ELSE()
SET(KWSYS_BUILD_SHARED 0)
SET(KWSYS_LIBRARY_TYPE STATIC)
ENDIF()
if(NOT DEFINED KWSYS_BUILD_PIC)
set(KWSYS_BUILD_PIC 0)
endif()
#-----------------------------------------------------------------------------
# Configure some implementation details.
KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T
"Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT)
KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T
"Checking whether C compiler has ssize_t in unistd.h" DIRECT)
IF(KWSYS_USE_Process)
KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC
"Checking whether C compiler has clock_gettime" DIRECT)
ENDIF()
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} -DKWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC=${KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC}"
)
IF(DEFINED KWSYS_PROCESS_USE_SELECT)
GET_PROPERTY(ProcessUNIX_FLAGS SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS)
SET_PROPERTY(SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS "${ProcessUNIX_FLAGS} -DKWSYSPE_USE_SELECT=${KWSYSPE_USE_SELECT}")
ENDIF()
IF(KWSYS_USE_DynamicLoader)
GET_PROPERTY(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
IF(KWSYS_SUPPORTS_SHARED_LIBS)
SET(KWSYS_SUPPORTS_SHARED_LIBS 1)
ELSE()
SET(KWSYS_SUPPORTS_SHARED_LIBS 0)
ENDIF()
SET_PROPERTY(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS
KWSYS_SUPPORTS_SHARED_LIBS=${KWSYS_SUPPORTS_SHARED_LIBS})
ENDIF()
IF(KWSYS_USE_SystemTools)
if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
endif ()
if (KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
else ()
set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 0)
endif ()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV
"Checking whether CXX compiler has setenv" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV
"Checking whether CXX compiler has unsetenv" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
"Checking whether CXX compiler has environ in stdlib.h" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMES
"Checking whether CXX compiler has utimes" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMENSAT
"Checking whether CXX compiler has utimensat" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIM
"Checking whether CXX compiler struct stat has st_mtim member" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
"Checking whether CXX compiler struct stat has st_mtimespec member" DIRECT)
SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV}
KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV}
KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H}
KWSYS_CXX_HAS_UTIMES=${KWSYS_CXX_HAS_UTIMES}
KWSYS_CXX_HAS_UTIMENSAT=${KWSYS_CXX_HAS_UTIMENSAT}
KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM}
KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC}
)
IF(NOT WIN32)
IF(KWSYS_STANDALONE)
OPTION(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON)
ENDIF()
IF(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES)
SET_PROPERTY(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES
)
ENDIF()
ENDIF()
# Disable getpwnam for static linux builds since it depends on shared glibc
GET_PROPERTY(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
IF(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT SHARED_LIBS_SUPPORTED)
SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS
HAVE_GETPWNAM=0
)
ENDIF()
ENDIF()
IF(KWSYS_USE_SystemInformation)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P})
IF(NOT CYGWIN)
INCLUDE(CheckIncludeFiles)
CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H)
IF(KWSYS_SYS_HAS_IFADDRS_H)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_SYS_HAS_IFADDRS_H=1)
ENDIF()
ENDIF()
IF(WIN32)
INCLUDE(CheckSymbolExists)
SET(CMAKE_REQUIRED_LIBRARIES Psapi)
CHECK_SYMBOL_EXISTS(GetProcessMemoryInfo "windows.h;psapi.h" KWSYS_SYS_HAS_PSAPI)
UNSET(CMAKE_REQUIRED_LIBRARIES)
IF(KWSYS_SYS_HAS_PSAPI)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_SYS_HAS_PSAPI=1)
IF(MSVC70 OR MSVC71)
# Suppress LNK4089: all references to 'PSAPI.DLL' discarded by /OPT:REF
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089")
ENDIF()
ENDIF()
ENDIF()
IF(CMAKE_SYSTEM MATCHES "HP-UX")
CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H)
IF(KWSYS_SYS_HAS_MPCTL_H)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1)
ENDIF()
ENDIF()
IF(CMAKE_SYSTEM MATCHES "BSD")
CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H)
IF(KWSYS_SYS_HAS_MACHINE_CPU_H)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1)
ENDIF()
ENDIF()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64
"Checking whether CXX compiler has rlimit64" DIRECT)
SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
IF(KWSYS_CXX_HAS_RLIMIT64)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1)
ENDIF()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOL
"Checking whether CXX compiler has atol" DIRECT)
IF(KWSYS_CXX_HAS_ATOL)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1)
ENDIF()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOLL
"Checking whether CXX compiler has atoll" DIRECT)
IF(KWSYS_CXX_HAS_ATOLL)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1)
ENDIF()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS__ATOI64
"Checking whether CXX compiler has _atoi64" DIRECT)
IF(KWSYS_CXX_HAS__ATOI64)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1)
ENDIF()
IF(UNIX)
INCLUDE(CheckIncludeFileCXX)
# check for simple stack trace
# usually it's in libc but on FreeBSD
# it's in libexecinfo
FIND_LIBRARY(EXECINFO_LIB "execinfo")
MARK_AS_ADVANCED(EXECINFO_LIB)
IF (NOT EXECINFO_LIB)
SET(EXECINFO_LIB "")
ENDIF()
CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH)
IF (KWSYS_CXX_HAS_EXECINFOH)
# we have the backtrace header check if it
# can be used with this compiler
SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB})
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE
"Checking whether backtrace works with this C++ compiler" DIRECT)
SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
IF (KWSYS_CXX_HAS_BACKTRACE)
# backtrace is supported by this system and compiler.
# now check for the more advanced capabilities.
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1)
# check for symbol lookup using dladdr
CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH)
IF (KWSYS_CXX_HAS_DLFCNH)
# we have symbol lookup libraries and headers
# check if they can be used with this compiler
SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS})
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR
"Checking whether dladdr works with this C++ compiler" DIRECT)
SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES)
IF (KWSYS_CXX_HAS_DLADDR)
# symbol lookup is supported by this system
# and compiler.
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1)
ENDIF()
ENDIF()
# c++ demangling support
# check for cxxabi headers
CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH)
IF (KWSYS_CXX_HAS_CXXABIH)
# check if cxxabi can be used with this
# system and compiler.
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI
"Checking whether cxxabi works with this C++ compiler" DIRECT)
IF (KWSYS_CXX_HAS_CXXABI)
# c++ demangle using cxxabi is supported with
# this system and compiler
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1)
ENDIF()
ENDIF()
# basic backtrace works better with release build
# don't bother with advanced features for release
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1)
ENDIF()
ENDIF()
ENDIF()
IF(BORLAND)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM
"Checking whether Borland CXX compiler supports assembler instructions" DIRECT)
IF(KWSYS_CXX_HAS_BORLAND_ASM)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM=1)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM_CPUID
"Checking whether Borland CXX compiler supports CPUID assembler instruction" DIRECT)
IF(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM_CPUID=1)
ENDIF()
ENDIF()
ENDIF()
IF(KWSYS_USE___INT64)
SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_USE___INT64=1)
ENDIF()
IF(KWSYS_USE_LONG_LONG)
SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=1)
ENDIF()
IF(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM_LONG_LONG=1)
ENDIF()
IF(KWSYS_IOS_HAS_OSTREAM___INT64)
SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1)
ENDIF()
IF(KWSYS_BUILD_SHARED)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1)
ENDIF()
IF(UNIX AND NOT CYGWIN)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG
"Checking whether CXX compiler has getloadavg" DIRECT)
IF(KWSYS_CXX_HAS_GETLOADAVG)
SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY
COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1)
ENDIF()
ENDIF()
ENDIF()
IF(KWSYS_USE_FStream)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H
"Checking whether <ext/stdio_filebuf.h> is available" DIRECT)
ENDIF()
#-----------------------------------------------------------------------------
# Choose a directory for the generated headers.
IF(NOT KWSYS_HEADER_ROOT)
SET(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}")
ENDIF()
SET(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}")
INCLUDE_DIRECTORIES(${KWSYS_HEADER_ROOT})
#-----------------------------------------------------------------------------
IF(KWSYS_INSTALL_DOC_DIR)
# Assign the license to the runtime component since it must be
# distributed with binary forms of this software.
IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME)
SET(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS}
COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME}
)
ENDIF()
# Install the license under the documentation directory.
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt
DESTINATION ${KWSYS_INSTALL_DOC_DIR}/${KWSYS_NAMESPACE}
${KWSYS_INSTALL_LICENSE_OPTIONS})
ENDIF()
#-----------------------------------------------------------------------------
# Build a list of classes and headers we need to implement the
# selected components. Initialize with required components.
SET(KWSYS_CLASSES)
SET(KWSYS_H_FILES Configure SharedForward)
SET(KWSYS_HXX_FILES Configure String)
IF(NOT CMake_SOURCE_DIR)
SET(KWSYS_HXX_FILES ${KWSYS_HXX_FILES}
hashtable hash_fun hash_map hash_set
)
ENDIF()
# Add selected C++ classes.
SET(cppclasses
Directory DynamicLoader Encoding Glob RegularExpression SystemTools
CommandLineArguments IOStream FStream SystemInformation ConsoleBuf
)
FOREACH(cpp ${cppclasses})
IF(KWSYS_USE_${cpp})
# Use the corresponding class.
SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp})
# Load component-specific CMake code.
IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake)
ENDIF()
ENDIF()
ENDFOREACH()
# Add selected C components.
FOREACH(c
Process Base64 Encoding MD5 Terminal System String
)
IF(KWSYS_USE_${c})
# Use the corresponding header file.
SET(KWSYS_H_FILES ${KWSYS_H_FILES} ${c})
# Load component-specific CMake code.
IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake)
ENDIF()
ENDIF()
ENDFOREACH()
#-----------------------------------------------------------------------------
# Build a list of sources for the library based on components that are
# included.
SET(KWSYS_C_SRCS)
SET(KWSYS_CXX_SRCS)
# Add the proper sources for this platform's Process implementation.
IF(KWSYS_USE_Process)
IF(NOT UNIX)
# Use the Windows implementation.
SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c)
ELSE()
# Use the UNIX implementation.
SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c)
ENDIF()
ENDIF()
# Add selected C sources.
FOREACH(c Base64 Encoding MD5 Terminal System String)
IF(KWSYS_USE_${c})
IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c)
LIST(APPEND KWSYS_C_SRCS ${c}C.c)
ELSE()
LIST(APPEND KWSYS_C_SRCS ${c}.c)
ENDIF()
ENDIF()
ENDFOREACH()
# Configure headers of C++ classes and construct the list of sources.
FOREACH(c ${KWSYS_CLASSES})
# Add this source to the list of source files for the library.
IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx)
LIST(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx)
ELSEIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx)
LIST(APPEND KWSYS_CXX_SRCS ${c}.cxx)
ENDIF()
# Configure the header for this class.
CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx
@ONLY IMMEDIATE)
SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx)
# Create an install target for the header.
IF(KWSYS_INSTALL_INCLUDE_DIR)
INSTALL(FILES ${KWSYS_HEADER_DIR}/${c}.hxx
DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
${KWSYS_INSTALL_INCLUDE_OPTIONS})
ENDIF()
ENDFOREACH()
# Configure C headers.
FOREACH(h ${KWSYS_H_FILES})
# Configure the header into the given directory.
CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h
@ONLY IMMEDIATE)
SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h)
# Create an install target for the header.
IF(KWSYS_INSTALL_INCLUDE_DIR)
INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.h
DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
${KWSYS_INSTALL_INCLUDE_OPTIONS})
ENDIF()
ENDFOREACH()
# Configure other C++ headers.
FOREACH(h ${KWSYS_HXX_FILES})
# Configure the header into the given directory.
CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx
@ONLY IMMEDIATE)
SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx)
# Create an install target for the header.
IF(KWSYS_INSTALL_INCLUDE_DIR)
INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.hxx
DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE}
${KWSYS_INSTALL_INCLUDE_OPTIONS})
ENDIF()
ENDFOREACH()
#-----------------------------------------------------------------------------
# Add the library with the configured name and list of sources.
IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS)
IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE)
SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE})
SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}_objects)
SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}_private)
SET(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_INTERFACE} ${KWSYS_TARGET_LINK})
SET(KWSYS_LINK_DEPENDENCY INTERFACE)
ADD_LIBRARY(${KWSYS_TARGET_OBJECT} OBJECT
${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS})
IF(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC)
SET_PROPERTY(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY
POSITION_INDEPENDENT_CODE TRUE)
ENDIF()
ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} INTERFACE)
ADD_LIBRARY(${KWSYS_TARGET_LINK} INTERFACE)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_LINK} INTERFACE
${KWSYS_TARGET_INTERFACE})
TARGET_SOURCES(${KWSYS_TARGET_LINK} INTERFACE
$<TARGET_OBJECTS:${KWSYS_TARGET_OBJECT}>)
target_compile_features(${KWSYS_TARGET_OBJECT} PRIVATE ${KWSYS_CXX_COMPILE_FEATURES})
target_compile_features(${KWSYS_TARGET_INTERFACE} INTERFACE ${KWSYS_CXX_COMPILE_FEATURES})
ELSE()
SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE})
SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE})
SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE})
set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_LINK})
SET(KWSYS_LINK_DEPENDENCY PUBLIC)
ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} ${KWSYS_LIBRARY_TYPE}
${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS})
target_compile_features(${KWSYS_TARGET_INTERFACE} PUBLIC ${KWSYS_CXX_COMPILE_FEATURES})
ENDIF()
if (KWSYS_ALIAS_TARGET)
add_library(${KWSYS_ALIAS_TARGET} ALIAS ${KWSYS_TARGET_INTERFACE})
endif ()
SET_TARGET_PROPERTIES(${KWSYS_TARGET_OBJECT} PROPERTIES
C_CLANG_TIDY ""
CXX_CLANG_TIDY ""
C_INCLUDE_WHAT_YOU_USE ""
CXX_INCLUDE_WHAT_YOU_USE ""
LABELS "${KWSYS_LABELS_LIB}")
IF(KWSYS_USE_DynamicLoader)
IF(UNIX)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
${CMAKE_DL_LIBS})
ENDIF()
ENDIF()
IF(KWSYS_USE_SystemInformation)
IF(WIN32)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32)
# link in dbghelp.dll for symbol lookup if MSVC 1800 or later
# Note that the dbghelp runtime is part of MS Windows OS
IF(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp)
ENDIF()
IF(KWSYS_SYS_HAS_PSAPI)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
Psapi)
ENDIF()
ELSEIF(UNIX)
IF (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE)
# backtrace on FreeBSD is not in libc
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
${EXECINFO_LIB})
ENDIF()
IF (KWSYS_CXX_HAS_DLADDR)
# for symbol lookup using dladdr
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
${CMAKE_DL_LIBS})
ENDIF()
IF (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
socket)
ENDIF()
ENDIF()
ENDIF()
# Apply user-defined target properties to the library.
IF(KWSYS_PROPERTIES_CXX)
SET_TARGET_PROPERTIES(${KWSYS_TARGET_INTERFACE} PROPERTIES
${KWSYS_PROPERTIES_CXX})
ENDIF()
# Set up include usage requirement
IF(COMMAND TARGET_INCLUDE_DIRECTORIES)
TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE
$<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>)
IF(KWSYS_INSTALL_INCLUDE_DIR)
TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE
$<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>)
ENDIF()
ENDIF()
# Create an install target for the library.
IF(KWSYS_INSTALL_LIBRARY_RULE)
INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_RULE})
ENDIF()
IF(KWSYS_INSTALL_NAMELINK_RULE)
INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_NAMELINK_RULE})
ENDIF()
ENDIF()
# Add a C-only library if requested.
IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS)
IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE)
SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c)
SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_objects)
SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c_private)
SET(KWSYS_TARGET_C_INSTALL
${KWSYS_TARGET_C_INTERFACE} ${KWSYS_TARGET_C_LINK})
SET(KWSYS_LINK_DEPENDENCY INTERFACE)
ADD_LIBRARY(${KWSYS_TARGET_C_OBJECT} OBJECT ${KWSYS_C_SRCS})
IF(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC)
SET_PROPERTY(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY
POSITION_INDEPENDENT_CODE TRUE)
ENDIF()
ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} INTERFACE)
ADD_LIBRARY(${KWSYS_TARGET_C_LINK} INTERFACE)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_C_LINK} INTERFACE
${KWSYS_TARGET_C_INTERFACE})
TARGET_SOURCES(${KWSYS_TARGET_C_LINK} INTERFACE
$<TARGET_OBJECTS:${KWSYS_TARGET_C_OBJECT}>)
ELSE()
SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c)
SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c)
SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c)
SET(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_LINK})
SET(KWSYS_LINK_DEPENDENCY PUBLIC)
ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} ${KWSYS_LIBRARY_TYPE}
${KWSYS_C_SRCS})
ENDIF()
SET_TARGET_PROPERTIES(${KWSYS_TARGET_C_OBJECT} PROPERTIES
LABELS "${KWSYS_LABELS_LIB}")
# Apply user-defined target properties to the library.
IF(KWSYS_PROPERTIES_C)
SET_TARGET_PROPERTIES(${KWSYS_TARGET_C_INTERFACE} PROPERTIES
${KWSYS_PROPERTIES_C})
ENDIF()
# Set up include usage requirement
IF(COMMAND TARGET_INCLUDE_DIRECTORIES)
TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE
$<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>)
IF(KWSYS_INSTALL_INCLUDE_DIR)
TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE
$<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>)
ENDIF()
ENDIF()
# Create an install target for the library.
IF(KWSYS_INSTALL_LIBRARY_RULE)
INSTALL(TARGETS ${KWSYS_TARGET_C_INSTALL})
ENDIF()
ENDIF()
# For building kwsys itself, we use a macro defined on the command
# line to configure the namespace in the C and C++ source files.
ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}")
# Disable deprecation warnings for standard C functions.
IF(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR
(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"))))
ADD_DEFINITIONS(
-D_CRT_NONSTDC_NO_DEPRECATE
-D_CRT_SECURE_NO_DEPRECATE
-D_CRT_SECURE_NO_WARNINGS
-D_SCL_SECURE_NO_DEPRECATE
)
ENDIF()
IF(WIN32)
# Help enforce the use of wide Windows apis.
ADD_DEFINITIONS(-DUNICODE -D_UNICODE)
ENDIF()
IF(KWSYS_USE_String)
# Activate code in "String.c". See the comment in the source.
SET_SOURCE_FILES_PROPERTIES(String.c PROPERTIES
COMPILE_FLAGS "-DKWSYS_STRING_C")
ENDIF()
IF(KWSYS_USE_Encoding)
# Set default 8 bit encoding in "EndcodingC.c".
SET_PROPERTY(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS
KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
ENDIF()
#-----------------------------------------------------------------------------
# Setup testing if not being built as part of another project.
IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
IF(BUILD_TESTING)
# Compute the location of executables.
SET(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}")
IF(EXECUTABLE_OUTPUT_PATH)
SET(EXEC_DIR "${EXECUTABLE_OUTPUT_PATH}")
ENDIF()
# C tests
SET(KWSYS_C_TESTS
testEncode.c
testTerminal.c
)
IF(KWSYS_STANDALONE)
SET(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c)
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_TARGET_C_LINK})
FOREACH(testfile ${KWSYS_C_TESTS})
get_filename_component(test "${testfile}" NAME_WE)
ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}})
SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
ENDFOREACH()
# C++ tests
IF(NOT WATCOM AND NOT CMake_SOURCE_DIR)
SET(KWSYS_CXX_TESTS
testHashSTL.cxx
)
ENDIF()
SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
testConfigure.cxx
testSystemTools.cxx
testCommandLineArguments.cxx
testCommandLineArguments1.cxx
testDirectory.cxx
)
IF(KWSYS_STL_HAS_WSTRING)
SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
testEncoding.cxx
)
ENDIF()
IF(KWSYS_USE_FStream)
SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
testFStream.cxx
)
ENDIF()
IF(KWSYS_USE_ConsoleBuf)
ADD_EXECUTABLE(testConsoleBufChild testConsoleBufChild.cxx)
SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_CLANG_TIDY "")
SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_CLANG_TIDY "")
SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_INCLUDE_WHAT_YOU_USE "")
SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
SET_PROPERTY(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE})
TARGET_LINK_LIBRARIES(testConsoleBufChild ${KWSYS_TARGET_LINK})
SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
testConsoleBuf.cxx
)
IF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND
CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506")
set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8)
ENDIF()
SET_PROPERTY(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS
KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
ENDIF()
IF(KWSYS_USE_SystemInformation)
SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.cxx)
ENDIF()
IF(KWSYS_USE_DynamicLoader)
SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader.cxx)
# 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_TARGET_INTERFACE})
if (WIN32)
# Windows tests supported flags.
add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c)
set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB})
set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl)
set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE})
add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c)
set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB})
set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE})
target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl)
endif ()
ENDIF()
CREATE_TEST_SOURCELIST(
KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
${KWSYS_CXX_TESTS}
)
ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS})
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_CLANG_TIDY "")
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_CLANG_TIDY "")
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "")
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE})
TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_TARGET_LINK})
SET(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
SET(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
CONFIGURE_FILE(
${PROJECT_SOURCE_DIR}/testSystemTools.h.in
${PROJECT_BINARY_DIR}/testSystemTools.h)
INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR})
IF(CTEST_TEST_KWSYS)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
SET_DIRECTORY_PROPERTIES(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake")
ENDIF()
SET(KWSYS_TEST_ARGS_testCommandLineArguments
--another-bool-variable
--long3=opt
--set-bool-arg1
-SSS ken brad bill andy
--some-bool-variable=true
--some-double-variable12.5
--some-int-variable 14
"--some-string-variable=test string with space"
--some-multi-argument 5 1 8 3 7 1 3 9 7 1
-N 12.5 -SS=andy -N 1.31 -N 22
-SS=bill -BBtrue -SS=brad
-BBtrue
-BBfalse
-SS=ken
-A
-C=test
--long2 hello
)
SET(KWSYS_TEST_ARGS_testCommandLineArguments1
--ignored
-n 24
--second-ignored
"-m=test value"
third-ignored
-p
some junk at the end
)
FOREACH(testfile ${KWSYS_CXX_TESTS})
get_filename_component(test "${testfile}" NAME_WE)
ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}})
SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
ENDFOREACH()
# Process tests.
ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestProcess testProcess.c)
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE})
TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestProcess ${KWSYS_TARGET_C_LINK})
IF(NOT CYGWIN)
SET(KWSYS_TEST_PROCESS_7 7)
ENDIF()
FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10)
ADD_TEST(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n})
SET_PROPERTY(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST})
SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120)
ENDFOREACH()
SET(testProcess_COMPILE_FLAGS "")
# Some Apple compilers produce bad optimizations in this source.
IF(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$")
SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -O0")
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "XL")
# Tell IBM XL not to warn about our test infinite loop
IF(CMAKE_SYSTEM MATCHES "Linux.*ppc64le"
AND CMAKE_C_COMPILER_VERSION VERSION_LESS "16.1.0"
AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.1")
# v13.1.[1-6] on Linux ppc64le is clang based and does not accept
# the -qsuppress option, so just suppress all warnings.
SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -w")
ELSE()
SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010")
ENDIF()
ENDIF()
IF(CMAKE_C_FLAGS MATCHES "-fsanitize=")
SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -DCRASH_USING_ABORT")
ENDIF()
SET_PROPERTY(SOURCE testProcess.c PROPERTY COMPILE_FLAGS "${testProcess_COMPILE_FLAGS}")
# 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_TARGET_C_LINK})
ADD_TEST(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1)
SET_PROPERTY(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST})
# Configure some test properties.
IF(KWSYS_STANDALONE)
# We expect test to fail
SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES WILL_FAIL ON)
GET_TEST_PROPERTY(kwsys.testFail WILL_FAIL wfv)
SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value")
MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}")
ENDIF()
# Set up ctest custom configuration file.
CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in
${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY)
# Suppress known consistent failures on buggy systems.
IF(KWSYS_TEST_BOGUS_FAILURES)
SET_TESTS_PROPERTIES(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON)
ENDIF()
ENDIF()
ENDIF()
-49
View File
@@ -1,49 +0,0 @@
Contributing to KWSys
*********************
Patches
=======
KWSys is kept in its own Git repository and shared by several projects
via copies in their source trees. Changes to KWSys should not be made
directly in a host project, except perhaps in maintenance branches.
KWSys uses `Kitware's GitLab Instance`_ to manage development and code review.
To contribute patches:
#. Fork the upstream `KWSys Repository`_ into a personal account.
#. Base all new work on the upstream ``master`` branch.
#. Run ``./SetupForDevelopment.sh`` in new local work trees.
#. Create commits making incremental, distinct, logically complete changes.
#. Push a topic branch to a personal repository fork on GitLab.
#. Create a GitLab Merge Request targeting the upstream ``master`` branch.
Once changes are reviewed, tested, and integrated to KWSys upstream then
copies of KWSys within dependent projects can be updated to get the changes.
.. _`Kitware's GitLab Instance`: https://gitlab.kitware.com
.. _`KWSys Repository`: https://gitlab.kitware.com/utils/kwsys
Code Style
==========
We use `clang-format`_ version **6.0** to define our style for C++ code in
the KWSys source tree. See the `.clang-format`_ configuration file for
our style settings. Use the `clang-format.bash`_ script to format source
code. It automatically runs ``clang-format`` on the set of source files
for which we enforce style. The script also has options to format only
a subset of files, such as those that are locally modified.
.. _`clang-format`: http://clang.llvm.org/docs/ClangFormat.html
.. _`.clang-format`: .clang-format
.. _`clang-format.bash`: clang-format.bash
License
=======
We do not require any formal copyright assignment or contributor license
agreement. Any contributions intentionally sent upstream are presumed
to be offered under terms of the OSI-approved BSD 3-clause License.
See `Copyright.txt`_ for details.
.. _`Copyright.txt`: Copyright.txt
-9
View File
@@ -1,9 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
set(CTEST_PROJECT_NAME "KWSys")
set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "open.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=KWSys")
set(CTEST_DROP_SITE_CDASH TRUE)
@@ -1,14 +0,0 @@
# kwsys.testProcess-10 involves sending SIGINT to a child process, which then
# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess).
# Naturally, this results in plenty of memory being "leaked" by this child
# process - the memory check results are not meaningful in this case.
#
# kwsys.testProcess-9 also tests sending SIGINT to a child process. However,
# normal operation of that test involves the child process timing out, and the
# host process kills (SIGKILL) it as a result. Since it was SIGKILL'ed, the
# resulting memory leaks are not logged by valgrind anyway. Therefore, we
# don't have to exclude it.
list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE
kwsys.testProcess-10
)
@@ -1,768 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(CommandLineArguments.hxx)
#include KWSYS_HEADER(Configure.hxx)
#include KWSYS_HEADER(String.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "CommandLineArguments.hxx.in"
# include "Configure.hxx.in"
# include "String.hxx.in"
#endif
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
# pragma warning(disable : 4786)
#endif
#if defined(__sgi) && !defined(__GNUC__)
# pragma set woff 1375 /* base class destructor not virtual */
#endif
#if 0
# define CommandLineArguments_DEBUG(x) \
std::cout << __LINE__ << " CLA: " << x << std::endl
#else
# define CommandLineArguments_DEBUG(x)
#endif
namespace KWSYS_NAMESPACE {
struct CommandLineArgumentsCallbackStructure
{
const char* Argument;
int ArgumentType;
CommandLineArguments::CallbackType Callback;
void* CallData;
void* Variable;
int VariableType;
const char* Help;
};
class CommandLineArgumentsVectorOfStrings : public std::vector<kwsys::String>
{
};
class CommandLineArgumentsSetOfStrings : public std::set<kwsys::String>
{
};
class CommandLineArgumentsMapOfStrucs
: public std::map<kwsys::String, CommandLineArgumentsCallbackStructure>
{
};
class CommandLineArgumentsInternal
{
public:
CommandLineArgumentsInternal()
: UnknownArgumentCallback{ nullptr }
, ClientData{ nullptr }
, LastArgument{ 0 }
{
}
typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
typedef kwsys::String String;
typedef CommandLineArgumentsSetOfStrings SetOfStrings;
VectorOfStrings Argv;
String Argv0;
CallbacksMap Callbacks;
CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
void* ClientData;
VectorOfStrings::size_type LastArgument;
VectorOfStrings UnusedArguments;
};
CommandLineArguments::CommandLineArguments()
{
this->Internals = new CommandLineArguments::Internal;
this->Help = "";
this->LineLength = 80;
this->StoreUnusedArgumentsFlag = false;
}
CommandLineArguments::~CommandLineArguments()
{
delete this->Internals;
}
void CommandLineArguments::Initialize(int argc, const char* const argv[])
{
int cc;
this->Initialize();
this->Internals->Argv0 = argv[0];
for (cc = 1; cc < argc; cc++) {
this->ProcessArgument(argv[cc]);
}
}
void CommandLineArguments::Initialize(int argc, char* argv[])
{
this->Initialize(argc, static_cast<const char* const*>(argv));
}
void CommandLineArguments::Initialize()
{
this->Internals->Argv.clear();
this->Internals->LastArgument = 0;
}
void CommandLineArguments::ProcessArgument(const char* arg)
{
this->Internals->Argv.push_back(arg);
}
bool CommandLineArguments::GetMatchedArguments(
std::vector<std::string>* matches, const std::string& arg)
{
matches->clear();
CommandLineArguments::Internal::CallbacksMap::iterator it;
// Does the argument match to any we know about?
for (it = this->Internals->Callbacks.begin();
it != this->Internals->Callbacks.end(); it++) {
const CommandLineArguments::Internal::String& parg = it->first;
CommandLineArgumentsCallbackStructure* cs = &it->second;
if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) {
if (arg == parg) {
matches->push_back(parg);
}
} else if (arg.find(parg) == 0) {
matches->push_back(parg);
}
}
return !matches->empty();
}
int CommandLineArguments::Parse()
{
std::vector<std::string>::size_type cc;
std::vector<std::string> matches;
if (this->StoreUnusedArgumentsFlag) {
this->Internals->UnusedArguments.clear();
}
for (cc = 0; cc < this->Internals->Argv.size(); cc++) {
const std::string& arg = this->Internals->Argv[cc];
CommandLineArguments_DEBUG("Process argument: " << arg);
this->Internals->LastArgument = cc;
if (this->GetMatchedArguments(&matches, arg)) {
// Ok, we found one or more arguments that match what user specified.
// Let's find the longest one.
CommandLineArguments::Internal::VectorOfStrings::size_type kk;
CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0;
CommandLineArguments::Internal::String::size_type maxlen = 0;
for (kk = 0; kk < matches.size(); kk++) {
if (matches[kk].size() > maxlen) {
maxlen = matches[kk].size();
maxidx = kk;
}
}
// So, the longest one is probably the right one. Now see if it has any
// additional value
CommandLineArgumentsCallbackStructure* cs =
&this->Internals->Callbacks[matches[maxidx]];
const std::string& sarg = matches[maxidx];
if (cs->Argument != sarg) {
abort();
}
switch (cs->ArgumentType) {
case NO_ARGUMENT:
// No value
if (!this->PopulateVariable(cs, nullptr)) {
return 0;
}
break;
case SPACE_ARGUMENT:
if (cc == this->Internals->Argv.size() - 1) {
this->Internals->LastArgument--;
return 0;
}
CommandLineArguments_DEBUG("This is a space argument: "
<< arg << " value: "
<< this->Internals->Argv[cc + 1]);
// Value is the next argument
if (!this->PopulateVariable(cs,
this->Internals->Argv[cc + 1].c_str())) {
return 0;
}
cc++;
break;
case EQUAL_ARGUMENT:
if (arg.size() == sarg.size() || arg.at(sarg.size()) != '=') {
this->Internals->LastArgument--;
return 0;
}
// Value is everythng followed the '=' sign
if (!this->PopulateVariable(cs, arg.c_str() + sarg.size() + 1)) {
return 0;
}
break;
case CONCAT_ARGUMENT:
// Value is whatever follows the argument
if (!this->PopulateVariable(cs, arg.c_str() + sarg.size())) {
return 0;
}
break;
case MULTI_ARGUMENT:
// Suck in all the rest of the arguments
CommandLineArguments_DEBUG("This is a multi argument: " << arg);
for (cc++; cc < this->Internals->Argv.size(); ++cc) {
const std::string& marg = this->Internals->Argv[cc];
CommandLineArguments_DEBUG(
" check multi argument value: " << marg);
if (this->GetMatchedArguments(&matches, marg)) {
CommandLineArguments_DEBUG("End of multi argument "
<< arg << " with value: " << marg);
break;
}
CommandLineArguments_DEBUG(
" populate multi argument value: " << marg);
if (!this->PopulateVariable(cs, marg.c_str())) {
return 0;
}
}
if (cc != this->Internals->Argv.size()) {
CommandLineArguments_DEBUG("Again End of multi argument " << arg);
cc--;
continue;
}
break;
default:
std::cerr << "Got unknown argument type: \"" << cs->ArgumentType
<< "\"" << std::endl;
this->Internals->LastArgument--;
return 0;
}
} else {
// Handle unknown arguments
if (this->Internals->UnknownArgumentCallback) {
if (!this->Internals->UnknownArgumentCallback(
arg.c_str(), this->Internals->ClientData)) {
this->Internals->LastArgument--;
return 0;
}
return 1;
} else if (this->StoreUnusedArgumentsFlag) {
CommandLineArguments_DEBUG("Store unused argument " << arg);
this->Internals->UnusedArguments.push_back(arg);
} else {
std::cerr << "Got unknown argument: \"" << arg << "\"" << std::endl;
this->Internals->LastArgument--;
return 0;
}
}
}
return 1;
}
void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv)
{
CommandLineArguments::Internal::VectorOfStrings::size_type size =
this->Internals->Argv.size() - this->Internals->LastArgument + 1;
CommandLineArguments::Internal::VectorOfStrings::size_type cc;
// Copy Argv0 as the first argument
char** args = new char*[size];
args[0] = new char[this->Internals->Argv0.size() + 1];
strcpy(args[0], this->Internals->Argv0.c_str());
int cnt = 1;
// Copy everything after the LastArgument, since that was not parsed.
for (cc = this->Internals->LastArgument + 1;
cc < this->Internals->Argv.size(); cc++) {
args[cnt] = new char[this->Internals->Argv[cc].size() + 1];
strcpy(args[cnt], this->Internals->Argv[cc].c_str());
cnt++;
}
*argc = cnt;
*argv = args;
}
void CommandLineArguments::GetUnusedArguments(int* argc, char*** argv)
{
CommandLineArguments::Internal::VectorOfStrings::size_type size =
this->Internals->UnusedArguments.size() + 1;
CommandLineArguments::Internal::VectorOfStrings::size_type cc;
// Copy Argv0 as the first argument
char** args = new char*[size];
args[0] = new char[this->Internals->Argv0.size() + 1];
strcpy(args[0], this->Internals->Argv0.c_str());
int cnt = 1;
// Copy everything after the LastArgument, since that was not parsed.
for (cc = 0; cc < this->Internals->UnusedArguments.size(); cc++) {
kwsys::String& str = this->Internals->UnusedArguments[cc];
args[cnt] = new char[str.size() + 1];
strcpy(args[cnt], str.c_str());
cnt++;
}
*argc = cnt;
*argv = args;
}
void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv)
{
int cc;
for (cc = 0; cc < argc; ++cc) {
delete[](*argv)[cc];
}
delete[] * argv;
}
void CommandLineArguments::AddCallback(const char* argument,
ArgumentTypeEnum type,
CallbackType callback, void* call_data,
const char* help)
{
CommandLineArgumentsCallbackStructure s;
s.Argument = argument;
s.ArgumentType = type;
s.Callback = callback;
s.CallData = call_data;
s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
s.Variable = nullptr;
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 = nullptr;
s.CallData = nullptr;
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); \
}
/* clang-format off */
CommandLineArgumentsAddArgumentMacro(BOOL, bool)
CommandLineArgumentsAddArgumentMacro(INT, int)
CommandLineArgumentsAddArgumentMacro(DOUBLE, double)
CommandLineArgumentsAddArgumentMacro(STRING, char*)
CommandLineArgumentsAddArgumentMacro(STL_STRING, std::string)
CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL, std::vector<bool>)
CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector<int>)
CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, std::vector<double>)
CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, std::vector<char*>)
CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING,
std::vector<std::string>)
#ifdef HELP_CLANG_FORMAT
;
#endif
/* clang-format on */
#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); \
}
/* clang-format off */
CommandLineArgumentsAddBooleanArgumentMacro(BOOL, bool)
CommandLineArgumentsAddBooleanArgumentMacro(INT, int)
CommandLineArgumentsAddBooleanArgumentMacro(DOUBLE, double)
CommandLineArgumentsAddBooleanArgumentMacro(STRING, char*)
CommandLineArgumentsAddBooleanArgumentMacro(STL_STRING, std::string)
#ifdef HELP_CLANG_FORMAT
;
#endif
/* clang-format on */
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 nullptr;
}
// Since several arguments may point to the same argument, find the one this
// one point to if this one is pointing to another argument.
CommandLineArgumentsCallbackStructure* cs = &(it->second);
for (;;) {
CommandLineArguments::Internal::CallbacksMap::iterator hit =
this->Internals->Callbacks.find(cs->Help);
if (hit == this->Internals->Callbacks.end()) {
break;
}
cs = &(hit->second);
}
return cs->Help;
}
void CommandLineArguments::SetLineLength(unsigned int ll)
{
if (ll < 9 || ll > 1000) {
return;
}
this->LineLength = ll;
this->GenerateHelp();
}
const char* CommandLineArguments::GetArgv0()
{
return this->Internals->Argv0.c_str();
}
unsigned int CommandLineArguments::GetLastArgument()
{
return static_cast<unsigned int>(this->Internals->LastArgument + 1);
}
void CommandLineArguments::GenerateHelp()
{
std::ostringstream str;
// Collapse all arguments into the map of vectors of all arguments that do
// the same thing.
CommandLineArguments::Internal::CallbacksMap::iterator it;
typedef std::map<CommandLineArguments::Internal::String,
CommandLineArguments::Internal::SetOfStrings>
MapArgs;
MapArgs mp;
MapArgs::iterator mpit, smpit;
for (it = this->Internals->Callbacks.begin();
it != this->Internals->Callbacks.end(); it++) {
CommandLineArgumentsCallbackStructure* cs = &(it->second);
mpit = mp.find(cs->Help);
if (mpit != mp.end()) {
mpit->second.insert(it->first);
mp[it->first].insert(it->first);
} else {
mp[it->first].insert(it->first);
}
}
for (it = this->Internals->Callbacks.begin();
it != this->Internals->Callbacks.end(); it++) {
CommandLineArgumentsCallbackStructure* cs = &(it->second);
mpit = mp.find(cs->Help);
if (mpit != mp.end()) {
mpit->second.insert(it->first);
smpit = mp.find(it->first);
CommandLineArguments::Internal::SetOfStrings::iterator sit;
for (sit = smpit->second.begin(); sit != smpit->second.end(); sit++) {
mpit->second.insert(*sit);
}
mp.erase(smpit);
} else {
mp[it->first].insert(it->first);
}
}
// Find the length of the longest string
CommandLineArguments::Internal::String::size_type maxlen = 0;
for (mpit = mp.begin(); mpit != mp.end(); mpit++) {
CommandLineArguments::Internal::SetOfStrings::iterator sit;
for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) {
CommandLineArguments::Internal::String::size_type clen = sit->size();
switch (this->Internals->Callbacks[*sit].ArgumentType) {
case CommandLineArguments::NO_ARGUMENT:
clen += 0;
break;
case CommandLineArguments::CONCAT_ARGUMENT:
clen += 3;
break;
case CommandLineArguments::SPACE_ARGUMENT:
clen += 4;
break;
case CommandLineArguments::EQUAL_ARGUMENT:
clen += 4;
break;
}
if (clen > maxlen) {
maxlen = clen;
}
}
}
CommandLineArguments::Internal::String::size_type maxstrlen = maxlen;
maxlen += 4; // For the space before and after the option
// Print help for each option
for (mpit = mp.begin(); mpit != mp.end(); mpit++) {
CommandLineArguments::Internal::SetOfStrings::iterator sit;
for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) {
str << std::endl;
std::string argument = *sit;
switch (this->Internals->Callbacks[*sit].ArgumentType) {
case CommandLineArguments::NO_ARGUMENT:
break;
case CommandLineArguments::CONCAT_ARGUMENT:
argument += "opt";
break;
case CommandLineArguments::SPACE_ARGUMENT:
argument += " opt";
break;
case CommandLineArguments::EQUAL_ARGUMENT:
argument += "=opt";
break;
case CommandLineArguments::MULTI_ARGUMENT:
argument += " opt opt ...";
break;
}
str << " " << argument.substr(0, maxstrlen) << " ";
}
const char* ptr = this->Internals->Callbacks[mpit->first].Help;
size_t len = strlen(ptr);
int cnt = 0;
while (len > 0) {
// If argument with help is longer than line length, split it on previous
// space (or tab) and continue on the next line
CommandLineArguments::Internal::String::size_type cc;
for (cc = 0; ptr[cc]; cc++) {
if (*ptr == ' ' || *ptr == '\t') {
ptr++;
len--;
}
}
if (cnt > 0) {
for (cc = 0; cc < maxlen; cc++) {
str << " ";
}
}
CommandLineArguments::Internal::String::size_type skip = len;
if (skip > this->LineLength - maxlen) {
skip = this->LineLength - maxlen;
for (cc = skip - 1; cc > 0; cc--) {
if (ptr[cc] == ' ' || ptr[cc] == '\t') {
break;
}
}
if (cc != 0) {
skip = cc;
}
}
str.write(ptr, static_cast<std::streamsize>(skip));
str << std::endl;
ptr += skip;
len -= skip;
cnt++;
}
}
/*
// This can help debugging help string
str << endl;
unsigned int cc;
for ( cc = 0; cc < this->LineLength; cc ++ )
{
str << cc % 10;
}
str << endl;
*/
this->Help = str.str();
}
void CommandLineArguments::PopulateVariable(bool* variable,
const std::string& value)
{
if (value == "1" || value == "ON" || value == "on" || value == "On" ||
value == "TRUE" || value == "true" || value == "True" ||
value == "yes" || value == "Yes" || value == "YES") {
*variable = true;
} else {
*variable = false;
}
}
void CommandLineArguments::PopulateVariable(int* variable,
const std::string& value)
{
char* res = nullptr;
*variable = static_cast<int>(strtol(value.c_str(), &res, 10));
// if ( res && *res )
// {
// Can handle non-int
// }
}
void CommandLineArguments::PopulateVariable(double* variable,
const std::string& value)
{
char* res = nullptr;
*variable = strtod(value.c_str(), &res);
// if ( res && *res )
// {
// Can handle non-double
// }
}
void CommandLineArguments::PopulateVariable(char** variable,
const std::string& value)
{
delete[] * variable;
*variable = new char[value.size() + 1];
strcpy(*variable, value.c_str());
}
void CommandLineArguments::PopulateVariable(std::string* variable,
const std::string& value)
{
*variable = value;
}
void CommandLineArguments::PopulateVariable(std::vector<bool>* variable,
const std::string& value)
{
bool val = false;
if (value == "1" || value == "ON" || value == "on" || value == "On" ||
value == "TRUE" || value == "true" || value == "True" ||
value == "yes" || value == "Yes" || value == "YES") {
val = true;
}
variable->push_back(val);
}
void CommandLineArguments::PopulateVariable(std::vector<int>* variable,
const std::string& value)
{
char* res = nullptr;
variable->push_back(static_cast<int>(strtol(value.c_str(), &res, 10)));
// if ( res && *res )
// {
// Can handle non-int
// }
}
void CommandLineArguments::PopulateVariable(std::vector<double>* variable,
const std::string& value)
{
char* res = nullptr;
variable->push_back(strtod(value.c_str(), &res));
// if ( res && *res )
// {
// Can handle non-int
// }
}
void CommandLineArguments::PopulateVariable(std::vector<char*>* variable,
const std::string& value)
{
char* var = new char[value.size() + 1];
strcpy(var, value.c_str());
variable->push_back(var);
}
void CommandLineArguments::PopulateVariable(std::vector<std::string>* variable,
const std::string& value)
{
variable->push_back(value);
}
bool CommandLineArguments::PopulateVariable(
CommandLineArgumentsCallbackStructure* cs, const char* value)
{
// Call the callback
if (cs->Callback) {
if (!cs->Callback(cs->Argument, value, cs->CallData)) {
this->Internals->LastArgument--;
return 0;
}
}
CommandLineArguments_DEBUG("Set argument: " << cs->Argument << " to "
<< value);
if (cs->Variable) {
std::string var = "1";
if (value) {
var = value;
}
switch (cs->VariableType) {
case CommandLineArguments::INT_TYPE:
this->PopulateVariable(static_cast<int*>(cs->Variable), var);
break;
case CommandLineArguments::DOUBLE_TYPE:
this->PopulateVariable(static_cast<double*>(cs->Variable), var);
break;
case CommandLineArguments::STRING_TYPE:
this->PopulateVariable(static_cast<char**>(cs->Variable), var);
break;
case CommandLineArguments::STL_STRING_TYPE:
this->PopulateVariable(static_cast<std::string*>(cs->Variable), var);
break;
case CommandLineArguments::BOOL_TYPE:
this->PopulateVariable(static_cast<bool*>(cs->Variable), var);
break;
case CommandLineArguments::VECTOR_BOOL_TYPE:
this->PopulateVariable(static_cast<std::vector<bool>*>(cs->Variable),
var);
break;
case CommandLineArguments::VECTOR_INT_TYPE:
this->PopulateVariable(static_cast<std::vector<int>*>(cs->Variable),
var);
break;
case CommandLineArguments::VECTOR_DOUBLE_TYPE:
this->PopulateVariable(static_cast<std::vector<double>*>(cs->Variable),
var);
break;
case CommandLineArguments::VECTOR_STRING_TYPE:
this->PopulateVariable(static_cast<std::vector<char*>*>(cs->Variable),
var);
break;
case CommandLineArguments::VECTOR_STL_STRING_TYPE:
this->PopulateVariable(
static_cast<std::vector<std::string>*>(cs->Variable), var);
break;
default:
std::cerr << "Got unknown variable type: \"" << cs->VariableType
<< "\"" << std::endl;
this->Internals->LastArgument--;
return 0;
}
}
return 1;
}
} // namespace KWSYS_NAMESPACE
@@ -1,270 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_CommandLineArguments_hxx
#define @KWSYS_NAMESPACE@_CommandLineArguments_hxx
#include <@KWSYS_NAMESPACE@/Configure.h>
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <string>
#include <vector>
namespace @KWSYS_NAMESPACE@ {
class CommandLineArgumentsInternal;
struct CommandLineArgumentsCallbackStructure;
/** \class CommandLineArguments
* \brief Command line arguments processing code.
*
* Find specified arguments with optional options and execute specified methods
* or set given variables.
*
* The two interfaces it knows are callback based and variable based. For
* callback based, you have to register callback for particular argument using
* AddCallback method. When that argument is passed, the callback will be
* called with argument, value, and call data. For boolean (NO_ARGUMENT)
* arguments, the value is "1". If the callback returns 0 the argument parsing
* will stop with an error.
*
* For the variable interface you associate variable with each argument. When
* the argument is specified, the variable is set to the specified value casted
* to the appropriate type. For boolean (NO_ARGUMENT), the value is "1".
*
* Both interfaces can be used at the same time.
*
* Possible argument types are:
* NO_ARGUMENT - The argument takes no value : --A
* CONCAT_ARGUMENT - The argument takes value after no space : --Aval
* SPACE_ARGUMENT - The argument takes value after space : --A val
* EQUAL_ARGUMENT - The argument takes value after equal : --A=val
* MULTI_ARGUMENT - The argument takes values after space : --A val1 val2
* val3 ...
*
* Example use:
*
* kwsys::CommandLineArguments arg;
* arg.Initialize(argc, argv);
* typedef kwsys::CommandLineArguments argT;
* arg.AddArgument("--something", argT::EQUAL_ARGUMENT, &some_variable,
* "This is help string for --something");
* if ( !arg.Parse() )
* {
* std::cerr << "Problem parsing arguments" << std::endl;
* res = 1;
* }
*
*/
class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments
{
public:
CommandLineArguments();
~CommandLineArguments();
CommandLineArguments(const CommandLineArguments&) = delete;
CommandLineArguments& operator=(const CommandLineArguments&) = delete;
/**
* Various argument types.
*/
enum ArgumentTypeEnum
{
NO_ARGUMENT,
CONCAT_ARGUMENT,
SPACE_ARGUMENT,
EQUAL_ARGUMENT,
MULTI_ARGUMENT
};
/**
* Various variable types. When using the variable interface, this specifies
* what type the variable is.
*/
enum VariableTypeEnum
{
NO_VARIABLE_TYPE = 0, // The variable is not specified
INT_TYPE, // The variable is integer (int)
BOOL_TYPE, // The variable is boolean (bool)
DOUBLE_TYPE, // The variable is float (double)
STRING_TYPE, // The variable is string (char*)
STL_STRING_TYPE, // The variable is string (char*)
VECTOR_INT_TYPE, // The variable is integer (int)
VECTOR_BOOL_TYPE, // The variable is boolean (bool)
VECTOR_DOUBLE_TYPE, // The variable is float (double)
VECTOR_STRING_TYPE, // The variable is string (char*)
VECTOR_STL_STRING_TYPE, // The variable is string (char*)
LAST_VARIABLE_TYPE
};
/**
* Prototypes for callbacks for callback interface.
*/
typedef int (*CallbackType)(const char* argument, const char* value,
void* call_data);
typedef int (*ErrorCallbackType)(const char* argument, void* client_data);
/**
* Initialize internal data structures. This should be called before parsing.
*/
void Initialize(int argc, const char* const argv[]);
void Initialize(int argc, char* argv[]);
/**
* Initialize internal data structure and pass arguments one by one. This is
* convenience method for use from scripting languages where argc and argv
* are not available.
*/
void Initialize();
void ProcessArgument(const char* arg);
/**
* This method will parse arguments and call appropriate methods.
*/
int Parse();
/**
* This method will add a callback for a specific argument. The arguments to
* it are argument, argument type, callback method, and call data. The
* argument help specifies the help string used with this option. The
* callback and call_data can be skipped.
*/
void AddCallback(const char* argument, ArgumentTypeEnum type,
CallbackType callback, void* call_data, const char* help);
/**
* Add handler for argument which is going to set the variable to the
* specified value. If the argument is specified, the option is casted to the
* appropriate type.
*/
void AddArgument(const char* argument, ArgumentTypeEnum type, bool* variable,
const char* help);
void AddArgument(const char* argument, ArgumentTypeEnum type, int* variable,
const char* help);
void AddArgument(const char* argument, ArgumentTypeEnum type,
double* variable, const char* help);
void AddArgument(const char* argument, ArgumentTypeEnum type,
char** variable, const char* help);
void AddArgument(const char* argument, ArgumentTypeEnum type,
std::string* variable, const char* help);
/**
* Add handler for argument which is going to set the variable to the
* specified value. If the argument is specified, the option is casted to the
* appropriate type. This will handle the multi argument values.
*/
void AddArgument(const char* argument, ArgumentTypeEnum type,
std::vector<bool>* variable, const char* help);
void AddArgument(const char* argument, ArgumentTypeEnum type,
std::vector<int>* variable, const char* help);
void AddArgument(const char* argument, ArgumentTypeEnum type,
std::vector<double>* variable, const char* help);
void AddArgument(const char* argument, ArgumentTypeEnum type,
std::vector<char*>* variable, const char* help);
void AddArgument(const char* argument, ArgumentTypeEnum type,
std::vector<std::string>* variable, const char* help);
/**
* Add handler for boolean argument. The argument does not take any option
* and if it is specified, the value of the variable is true/1, otherwise it
* is false/0.
*/
void AddBooleanArgument(const char* argument, bool* variable,
const char* help);
void AddBooleanArgument(const char* argument, int* variable,
const char* help);
void AddBooleanArgument(const char* argument, double* variable,
const char* help);
void AddBooleanArgument(const char* argument, char** variable,
const char* help);
void AddBooleanArgument(const char* argument, std::string* variable,
const char* help);
/**
* Set the callbacks for error handling.
*/
void SetClientData(void* client_data);
void SetUnknownArgumentCallback(ErrorCallbackType callback);
/**
* Get remaining arguments. It allocates space for argv, so you have to call
* delete[] on it.
*/
void GetRemainingArguments(int* argc, char*** argv);
void DeleteRemainingArguments(int argc, char*** argv);
/**
* If StoreUnusedArguments is set to true, then all unknown arguments will be
* stored and the user can access the modified argc, argv without known
* arguments.
*/
void StoreUnusedArguments(bool val) { this->StoreUnusedArgumentsFlag = val; }
void GetUnusedArguments(int* argc, char*** argv);
/**
* Return string containing help. If the argument is specified, only return
* help for that argument.
*/
const char* GetHelp() { return this->Help.c_str(); }
const char* GetHelp(const char* arg);
/**
* Get / Set the help line length. This length is used when generating the
* help page. Default length is 80.
*/
void SetLineLength(unsigned int);
unsigned int GetLineLength();
/**
* Get the executable name (argv0). This is only available when using
* Initialize with argc/argv.
*/
const char* GetArgv0();
/**
* Get index of the last argument parsed. This is the last argument that was
* parsed ok in the original argc/argv list.
*/
unsigned int GetLastArgument();
protected:
void GenerateHelp();
//! This is internal method that registers variable with argument
void AddArgument(const char* argument, ArgumentTypeEnum type,
VariableTypeEnum vtype, void* variable, const char* help);
bool GetMatchedArguments(std::vector<std::string>* matches,
const std::string& arg);
//! Populate individual variables
bool PopulateVariable(CommandLineArgumentsCallbackStructure* cs,
const char* value);
//! Populate individual variables of type ...
void PopulateVariable(bool* variable, const std::string& value);
void PopulateVariable(int* variable, const std::string& value);
void PopulateVariable(double* variable, const std::string& value);
void PopulateVariable(char** variable, const std::string& value);
void PopulateVariable(std::string* variable, const std::string& value);
void PopulateVariable(std::vector<bool>* variable, const std::string& value);
void PopulateVariable(std::vector<int>* variable, const std::string& value);
void PopulateVariable(std::vector<double>* variable,
const std::string& value);
void PopulateVariable(std::vector<char*>* variable,
const std::string& value);
void PopulateVariable(std::vector<std::string>* variable,
const std::string& value);
typedef CommandLineArgumentsInternal Internal;
Internal* Internals;
std::string Help;
unsigned int LineLength;
bool StoreUnusedArgumentsFlag;
};
} // namespace @KWSYS_NAMESPACE@
#endif
-89
View File
@@ -1,89 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Configure_h
#define @KWSYS_NAMESPACE@_Configure_h
/* If we are building a kwsys .c or .cxx file, let it use the kwsys
namespace. When not building a kwsys source file these macros are
temporarily defined inside the headers that use them. */
#if defined(KWSYS_NAMESPACE)
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
/* Disable some warnings inside kwsys source files. */
#if defined(KWSYS_NAMESPACE)
# if defined(__BORLANDC__)
# pragma warn - 8027 /* function not inlined. */
# endif
# if defined(__INTEL_COMPILER)
# pragma warning(disable : 1572) /* floating-point equality test */
# endif
# if defined(__sgi) && !defined(__GNUC__)
# pragma set woff 3970 /* pointer to int conversion */
# pragma set woff 3968 /* 64 bit conversion */
# endif
#endif
/* Whether kwsys namespace is "kwsys". */
#define @KWSYS_NAMESPACE@_NAME_IS_KWSYS @KWSYS_NAME_IS_KWSYS@
/* Setup the export macro. */
#if @KWSYS_BUILD_SHARED@
# if defined(_WIN32) || defined(__CYGWIN__)
# if defined(@KWSYS_NAMESPACE@_EXPORTS)
# define @KWSYS_NAMESPACE@_EXPORT __declspec(dllexport)
# else
# define @KWSYS_NAMESPACE@_EXPORT __declspec(dllimport)
# endif
# elif __GNUC__ >= 4
# define @KWSYS_NAMESPACE@_EXPORT __attribute__((visibility("default")))
# else
# define @KWSYS_NAMESPACE@_EXPORT
# endif
#else
# define @KWSYS_NAMESPACE@_EXPORT
#endif
/* Enable warnings that are off by default but are useful. */
#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_ENABLE)
# if defined(_MSC_VER)
# pragma warning(default : 4263) /* no override, call convention differs \
*/
# endif
#endif
/* Disable warnings that are on by default but occur in valid code. */
#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE)
# if defined(_MSC_VER)
# pragma warning(disable : 4097) /* typedef is synonym for class */
# pragma warning(disable : 4127) /* conditional expression is constant */
# pragma warning(disable : 4244) /* possible loss in conversion */
# pragma warning(disable : 4251) /* missing DLL-interface */
# pragma warning(disable : 4305) /* truncation from type1 to type2 */
# pragma warning(disable : 4309) /* truncation of constant value */
# pragma warning(disable : 4514) /* unreferenced inline function */
# pragma warning(disable : 4706) /* assignment in conditional expression \
*/
# pragma warning(disable : 4710) /* function not inlined */
# pragma warning(disable : 4786) /* identifier truncated in debug info */
# endif
# if defined(__BORLANDC__) && !defined(__cplusplus)
/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an
unused parameter using "(param)" syntax (i.e. no cast to void). */
# pragma warn - 8019
# endif
#endif
/* MSVC 6.0 in release mode will warn about code it produces with its
optimizer. Disable the warnings specifically for this
configuration. Real warnings will be revealed by a debug build or
by other compilers. */
#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE_BOGUS)
# if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG)
# pragma warning(disable : 4701) /* Variable may be used uninitialized. */
# pragma warning(disable : 4702) /* Unreachable code. */
# endif
#endif
#endif
-65
View File
@@ -1,65 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Configure_hxx
#define @KWSYS_NAMESPACE@_Configure_hxx
/* Include C configuration. */
#include <@KWSYS_NAMESPACE@/Configure.h>
/* Whether wstring is available. */
#define @KWSYS_NAMESPACE@_STL_HAS_WSTRING @KWSYS_STL_HAS_WSTRING@
/* Whether <ext/stdio_filebuf.h> is available. */
#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \
@KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@
/* Whether the translation map is available or not. */
#define @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP \
@KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@
#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute)
# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x)
#elif defined(__has_cpp_attribute)
# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_cpp_attribute(x)
#else
# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) 0
#endif
#if __cplusplus >= 201103L
# define @KWSYS_NAMESPACE@_NULLPTR nullptr
#else
# define @KWSYS_NAMESPACE@_NULLPTR 0
#endif
#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH
# if __cplusplus >= 201703L && \
@KWSYS_NAMESPACE@__has_cpp_attribute(fallthrough)
# define @KWSYS_NAMESPACE@_FALLTHROUGH [[fallthrough]]
# elif __cplusplus >= 201103L && \
@KWSYS_NAMESPACE@__has_cpp_attribute(gnu::fallthrough)
# define @KWSYS_NAMESPACE@_FALLTHROUGH [[gnu::fallthrough]]
# elif __cplusplus >= 201103L && \
@KWSYS_NAMESPACE@__has_cpp_attribute(clang::fallthrough)
# define @KWSYS_NAMESPACE@_FALLTHROUGH [[clang::fallthrough]]
# endif
#endif
#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH
# define @KWSYS_NAMESPACE@_FALLTHROUGH static_cast<void>(0)
#endif
#undef @KWSYS_NAMESPACE@__has_cpp_attribute
/* If building a C++ file in kwsys itself, give the source file
access to the macros without a configured namespace. */
#if defined(KWSYS_NAMESPACE)
# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsys @KWSYS_NAMESPACE@
# endif
# define KWSYS_NAME_IS_KWSYS @KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING
# define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H \
@KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H
# define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH
# define KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP \
@KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP
#endif
#endif
-398
View File
@@ -1,398 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_ConsoleBuf_hxx
#define @KWSYS_NAMESPACE@_ConsoleBuf_hxx
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <@KWSYS_NAMESPACE@/Encoding.hxx>
#include <cstring>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <streambuf>
#include <string>
#if defined(_WIN32)
# include <windows.h>
# if __cplusplus >= 201103L
# include <system_error>
# endif
#endif
namespace @KWSYS_NAMESPACE@ {
#if defined(_WIN32)
template <class CharT, class Traits = std::char_traits<CharT> >
class BasicConsoleBuf : public std::basic_streambuf<CharT, Traits>
{
public:
typedef typename Traits::int_type int_type;
typedef typename Traits::char_type char_type;
class Manager
{
public:
Manager(std::basic_ios<CharT, Traits>& ios, const bool err = false)
: m_consolebuf(0)
{
m_ios = &ios;
try {
m_consolebuf = new BasicConsoleBuf<CharT, Traits>(err);
m_streambuf = m_ios->rdbuf(m_consolebuf);
} catch (const std::runtime_error& ex) {
std::cerr << "Failed to create ConsoleBuf!" << std::endl
<< ex.what() << std::endl;
};
}
BasicConsoleBuf<CharT, Traits>* GetConsoleBuf() { return m_consolebuf; }
void SetUTF8Pipes()
{
if (m_consolebuf) {
m_consolebuf->input_pipe_codepage = CP_UTF8;
m_consolebuf->output_pipe_codepage = CP_UTF8;
m_consolebuf->activateCodepageChange();
}
}
~Manager()
{
if (m_consolebuf) {
delete m_consolebuf;
m_ios->rdbuf(m_streambuf);
}
}
private:
std::basic_ios<CharT, Traits>* m_ios;
std::basic_streambuf<CharT, Traits>* m_streambuf;
BasicConsoleBuf<CharT, Traits>* m_consolebuf;
};
BasicConsoleBuf(const bool err = false)
: flush_on_newline(true)
, input_pipe_codepage(0)
, output_pipe_codepage(0)
, input_file_codepage(CP_UTF8)
, output_file_codepage(CP_UTF8)
, m_consolesCodepage(0)
{
m_hInput = ::GetStdHandle(STD_INPUT_HANDLE);
checkHandle(true, "STD_INPUT_HANDLE");
if (!setActiveInputCodepage()) {
throw std::runtime_error("setActiveInputCodepage failed!");
}
m_hOutput = err ? ::GetStdHandle(STD_ERROR_HANDLE)
: ::GetStdHandle(STD_OUTPUT_HANDLE);
checkHandle(false, err ? "STD_ERROR_HANDLE" : "STD_OUTPUT_HANDLE");
if (!setActiveOutputCodepage()) {
throw std::runtime_error("setActiveOutputCodepage failed!");
}
_setg();
_setp();
}
~BasicConsoleBuf() throw() { sync(); }
bool activateCodepageChange()
{
return setActiveInputCodepage() && setActiveOutputCodepage();
}
protected:
virtual int sync()
{
bool success = true;
if (m_hInput && m_isConsoleInput &&
::FlushConsoleInputBuffer(m_hInput) == 0) {
success = false;
}
if (m_hOutput && !m_obuffer.empty()) {
const std::wstring wbuffer = getBuffer(m_obuffer);
if (m_isConsoleOutput) {
DWORD charsWritten;
success =
::WriteConsoleW(m_hOutput, wbuffer.c_str(), (DWORD)wbuffer.size(),
&charsWritten, nullptr) == 0
? false
: true;
} else {
DWORD bytesWritten;
std::string buffer;
success = encodeOutputBuffer(wbuffer, buffer);
if (success) {
success =
::WriteFile(m_hOutput, buffer.c_str(), (DWORD)buffer.size(),
&bytesWritten, nullptr) == 0
? false
: true;
}
}
}
m_ibuffer.clear();
m_obuffer.clear();
_setg();
_setp();
return success ? 0 : -1;
}
virtual int_type underflow()
{
if (this->gptr() >= this->egptr()) {
if (!m_hInput) {
_setg(true);
return Traits::eof();
}
if (m_isConsoleInput) {
// ReadConsole doesn't tell if there's more input available
// don't support reading more characters than this
wchar_t wbuffer[8192];
DWORD charsRead;
if (ReadConsoleW(m_hInput, wbuffer,
(sizeof(wbuffer) / sizeof(wbuffer[0])), &charsRead,
nullptr) == 0 ||
charsRead == 0) {
_setg(true);
return Traits::eof();
}
setBuffer(std::wstring(wbuffer, charsRead), m_ibuffer);
} else {
std::wstring wbuffer;
std::string strbuffer;
DWORD bytesRead;
LARGE_INTEGER size;
if (GetFileSizeEx(m_hInput, &size) == 0) {
_setg(true);
return Traits::eof();
}
char* buffer = new char[size.LowPart];
while (ReadFile(m_hInput, buffer, size.LowPart, &bytesRead, nullptr) ==
0) {
if (GetLastError() == ERROR_MORE_DATA) {
strbuffer += std::string(buffer, bytesRead);
continue;
}
_setg(true);
delete[] buffer;
return Traits::eof();
}
if (bytesRead > 0) {
strbuffer += std::string(buffer, bytesRead);
}
delete[] buffer;
if (!decodeInputBuffer(strbuffer, wbuffer)) {
_setg(true);
return Traits::eof();
}
setBuffer(wbuffer, m_ibuffer);
}
_setg();
}
return Traits::to_int_type(*this->gptr());
}
virtual int_type overflow(int_type ch = Traits::eof())
{
if (!Traits::eq_int_type(ch, Traits::eof())) {
char_type chr = Traits::to_char_type(ch);
m_obuffer += chr;
if ((flush_on_newline && Traits::eq(chr, '\n')) ||
Traits::eq_int_type(ch, 0x00)) {
sync();
}
return ch;
}
sync();
return Traits::eof();
}
public:
bool flush_on_newline;
UINT input_pipe_codepage;
UINT output_pipe_codepage;
UINT input_file_codepage;
UINT output_file_codepage;
private:
HANDLE m_hInput;
HANDLE m_hOutput;
std::basic_string<char_type> m_ibuffer;
std::basic_string<char_type> m_obuffer;
bool m_isConsoleInput;
bool m_isConsoleOutput;
UINT m_activeInputCodepage;
UINT m_activeOutputCodepage;
UINT m_consolesCodepage;
void checkHandle(bool input, std::string handleName)
{
if ((input && m_hInput == INVALID_HANDLE_VALUE) ||
(!input && m_hOutput == INVALID_HANDLE_VALUE)) {
std::string errmsg =
"GetStdHandle(" + handleName + ") returned INVALID_HANDLE_VALUE";
# if __cplusplus >= 201103L
throw std::system_error(::GetLastError(), std::system_category(),
errmsg);
# else
throw std::runtime_error(errmsg);
# endif
}
}
UINT getConsolesCodepage()
{
if (!m_consolesCodepage) {
m_consolesCodepage = GetConsoleCP();
if (!m_consolesCodepage) {
m_consolesCodepage = GetACP();
}
}
return m_consolesCodepage;
}
bool setActiveInputCodepage()
{
m_isConsoleInput = false;
switch (GetFileType(m_hInput)) {
case FILE_TYPE_DISK:
m_activeInputCodepage = input_file_codepage;
break;
case FILE_TYPE_CHAR:
// Check for actual console.
DWORD consoleMode;
m_isConsoleInput =
GetConsoleMode(m_hInput, &consoleMode) == 0 ? false : true;
if (m_isConsoleInput) {
break;
}
@KWSYS_NAMESPACE@_FALLTHROUGH;
case FILE_TYPE_PIPE:
m_activeInputCodepage = input_pipe_codepage;
break;
default:
return false;
}
if (!m_isConsoleInput && m_activeInputCodepage == 0) {
m_activeInputCodepage = getConsolesCodepage();
}
return true;
}
bool setActiveOutputCodepage()
{
m_isConsoleOutput = false;
switch (GetFileType(m_hOutput)) {
case FILE_TYPE_DISK:
m_activeOutputCodepage = output_file_codepage;
break;
case FILE_TYPE_CHAR:
// Check for actual console.
DWORD consoleMode;
m_isConsoleOutput =
GetConsoleMode(m_hOutput, &consoleMode) == 0 ? false : true;
if (m_isConsoleOutput) {
break;
}
@KWSYS_NAMESPACE@_FALLTHROUGH;
case FILE_TYPE_PIPE:
m_activeOutputCodepage = output_pipe_codepage;
break;
default:
return false;
}
if (!m_isConsoleOutput && m_activeOutputCodepage == 0) {
m_activeOutputCodepage = getConsolesCodepage();
}
return true;
}
void _setg(bool empty = false)
{
if (!empty) {
this->setg((char_type*)m_ibuffer.data(), (char_type*)m_ibuffer.data(),
(char_type*)m_ibuffer.data() + m_ibuffer.size());
} else {
this->setg((char_type*)m_ibuffer.data(),
(char_type*)m_ibuffer.data() + m_ibuffer.size(),
(char_type*)m_ibuffer.data() + m_ibuffer.size());
}
}
void _setp()
{
this->setp((char_type*)m_obuffer.data(),
(char_type*)m_obuffer.data() + m_obuffer.size());
}
bool encodeOutputBuffer(const std::wstring wbuffer, std::string& buffer)
{
if (wbuffer.size() == 0) {
buffer = std::string();
return true;
}
const int length =
WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(),
(int)wbuffer.size(), nullptr, 0, nullptr, nullptr);
char* buf = new char[length];
const bool success =
WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(),
(int)wbuffer.size(), buf, length, nullptr,
nullptr) > 0
? true
: false;
buffer = std::string(buf, length);
delete[] buf;
return success;
}
bool decodeInputBuffer(const std::string buffer, std::wstring& wbuffer)
{
size_t length = buffer.length();
if (length == 0) {
wbuffer = std::wstring();
return true;
}
int actualCodepage = m_activeInputCodepage;
const char BOM_UTF8[] = { char(0xEF), char(0xBB), char(0xBF) };
const char* data = buffer.data();
const size_t BOMsize = sizeof(BOM_UTF8);
if (length >= BOMsize && std::memcmp(data, BOM_UTF8, BOMsize) == 0) {
// PowerShell uses UTF-8 with BOM for pipes
actualCodepage = CP_UTF8;
data += BOMsize;
length -= BOMsize;
}
const size_t wlength = static_cast<size_t>(MultiByteToWideChar(
actualCodepage, 0, data, static_cast<int>(length), nullptr, 0));
wchar_t* wbuf = new wchar_t[wlength];
const bool success =
MultiByteToWideChar(actualCodepage, 0, data, static_cast<int>(length),
wbuf, static_cast<int>(wlength)) > 0
? true
: false;
wbuffer = std::wstring(wbuf, wlength);
delete[] wbuf;
return success;
}
std::wstring getBuffer(const std::basic_string<char> buffer)
{
return Encoding::ToWide(buffer);
}
std::wstring getBuffer(const std::basic_string<wchar_t> buffer)
{
return buffer;
}
void setBuffer(const std::wstring wbuffer, std::basic_string<char>& target)
{
target = Encoding::ToNarrow(wbuffer);
}
void setBuffer(const std::wstring wbuffer,
std::basic_string<wchar_t>& target)
{
target = wbuffer;
}
}; // BasicConsoleBuf class
typedef BasicConsoleBuf<char> ConsoleBuf;
typedef BasicConsoleBuf<wchar_t> WConsoleBuf;
#endif
} // KWSYS_NAMESPACE
#endif
-38
View File
@@ -1,38 +0,0 @@
KWSys - Kitware System Library
Copyright 2000-2016 Kitware, Inc. and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Kitware, Inc. nor the names of Contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
The following individuals and institutions are among the Contributors:
* Insight Software Consortium <insightsoftwareconsortium.org>
See version control history for details of individual contributions.
-236
View File
@@ -1,236 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Directory.hxx)
#include KWSYS_HEADER(Configure.hxx)
#include KWSYS_HEADER(Encoding.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Configure.hxx.in"
# include "Directory.hxx.in"
# include "Encoding.hxx.in"
#endif
#include <string>
#include <vector>
namespace KWSYS_NAMESPACE {
class DirectoryInternals
{
public:
// Array of Files
std::vector<std::string> Files;
// Path to Open'ed directory
std::string Path;
};
Directory::Directory()
{
this->Internal = new DirectoryInternals;
}
Directory::~Directory()
{
delete this->Internal;
}
unsigned long Directory::GetNumberOfFiles() const
{
return static_cast<unsigned long>(this->Internal->Files.size());
}
const char* Directory::GetFile(unsigned long dindex) const
{
if (dindex >= this->Internal->Files.size()) {
return nullptr;
}
return this->Internal->Files[dindex].c_str();
}
const char* Directory::GetPath() const
{
return this->Internal->Path.c_str();
}
void Directory::Clear()
{
this->Internal->Path.resize(0);
this->Internal->Files.clear();
}
} // namespace KWSYS_NAMESPACE
// First Windows platforms
#if defined(_WIN32) && !defined(__CYGWIN__)
# include <windows.h>
# include <ctype.h>
# include <fcntl.h>
# include <io.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/stat.h>
# include <sys/types.h>
// Wide function names can vary depending on compiler:
# ifdef __BORLANDC__
# define _wfindfirst_func __wfindfirst
# define _wfindnext_func __wfindnext
# else
# define _wfindfirst_func _wfindfirst
# define _wfindnext_func _wfindnext
# endif
namespace KWSYS_NAMESPACE {
bool Directory::Load(const std::string& name)
{
this->Clear();
# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__)
// Older Visual C++ and Embarcadero compilers.
long srchHandle;
# else // Newer Visual C++
intptr_t srchHandle;
# endif
char* buf;
size_t n = name.size();
if (name.back() == '/' || name.back() == '\\') {
buf = new char[n + 1 + 1];
sprintf(buf, "%s*", name.c_str());
} else {
// Make sure the slashes in the wildcard suffix are consistent with the
// rest of the path
buf = new char[n + 2 + 1];
if (name.find('\\') != std::string::npos) {
sprintf(buf, "%s\\*", name.c_str());
} else {
sprintf(buf, "%s/*", name.c_str());
}
}
struct _wfinddata_t data; // data of current file
// Now put them into the file array
srchHandle = _wfindfirst_func(
(wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data);
delete[] buf;
if (srchHandle == -1) {
return 0;
}
// Loop through names
do {
this->Internal->Files.push_back(Encoding::ToNarrow(data.name));
} while (_wfindnext_func(srchHandle, &data) != -1);
this->Internal->Path = name;
return _findclose(srchHandle) != -1;
}
unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
{
# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__)
// Older Visual C++ and Embarcadero compilers.
long srchHandle;
# else // Newer Visual C++
intptr_t srchHandle;
# endif
char* buf;
size_t n = name.size();
if (name.back() == '/') {
buf = new char[n + 1 + 1];
sprintf(buf, "%s*", name.c_str());
} else {
buf = new char[n + 2 + 1];
sprintf(buf, "%s/*", name.c_str());
}
struct _wfinddata_t data; // data of current file
// Now put them into the file array
srchHandle =
_wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data);
delete[] buf;
if (srchHandle == -1) {
return 0;
}
// Loop through names
unsigned long count = 0;
do {
count++;
} while (_wfindnext_func(srchHandle, &data) != -1);
_findclose(srchHandle);
return count;
}
} // namespace KWSYS_NAMESPACE
#else
// Now the POSIX style directory access
# include <sys/types.h>
# include <dirent.h>
// PGI with glibc has trouble with dirent and large file support:
// http://www.pgroup.com/userforum/viewtopic.php?
// p=1992&sid=f16167f51964f1a68fe5041b8eb213b6
// Work around the problem by mapping dirent the same way as readdir.
# if defined(__PGI) && defined(__GLIBC__)
# define kwsys_dirent_readdir dirent
# define kwsys_dirent_readdir64 dirent64
# define kwsys_dirent kwsys_dirent_lookup(readdir)
# define kwsys_dirent_lookup(x) kwsys_dirent_lookup_delay(x)
# define kwsys_dirent_lookup_delay(x) kwsys_dirent_##x
# else
# define kwsys_dirent dirent
# endif
namespace KWSYS_NAMESPACE {
bool Directory::Load(const std::string& name)
{
this->Clear();
DIR* dir = opendir(name.c_str());
if (!dir) {
return 0;
}
for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) {
this->Internal->Files.push_back(d->d_name);
}
this->Internal->Path = name;
closedir(dir);
return 1;
}
unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
{
DIR* dir = opendir(name.c_str());
if (!dir) {
return 0;
}
unsigned long count = 0;
for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) {
count++;
}
closedir(dir);
return count;
}
} // namespace KWSYS_NAMESPACE
#endif
-72
View File
@@ -1,72 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Directory_hxx
#define @KWSYS_NAMESPACE@_Directory_hxx
#include <@KWSYS_NAMESPACE@/Configure.h>
#include <string>
namespace @KWSYS_NAMESPACE@ {
class DirectoryInternals;
/** \class Directory
* \brief Portable directory/filename traversal.
*
* Directory provides a portable way of finding the names of the files
* in a system directory.
*
* Directory currently works with Windows and Unix operating systems.
*/
class @KWSYS_NAMESPACE@_EXPORT Directory
{
public:
Directory();
~Directory();
/**
* Load the specified directory and load the names of the files
* in that directory. 0 is returned if the directory can not be
* opened, 1 if it is opened.
*/
bool Load(const std::string&);
/**
* Return the number of files in the current directory.
*/
unsigned long GetNumberOfFiles() const;
/**
* Return the number of files in the specified directory.
* A higher performance static method.
*/
static unsigned long GetNumberOfFilesInDirectory(const std::string&);
/**
* Return the file at the given index, the indexing is 0 based
*/
const char* GetFile(unsigned long) const;
/**
* Return the path to Open'ed directory
*/
const char* GetPath() const;
/**
* Clear the internal structure. Used internally at beginning of Load(...)
* to clear the cache.
*/
void Clear();
private:
// Private implementation details.
DirectoryInternals* Internal;
Directory(const Directory&); // Not implemented.
void operator=(const Directory&); // Not implemented.
}; // End Class: Directory
} // namespace @KWSYS_NAMESPACE@
#endif
-495
View File
@@ -1,495 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#if defined(_WIN32)
# define NOMINMAX // hide min,max to not conflict with <limits>
#endif
#include "kwsysPrivate.h"
#include KWSYS_HEADER(DynamicLoader.hxx)
#include KWSYS_HEADER(Configure.hxx)
#include KWSYS_HEADER(Encoding.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Configure.hxx.in"
# include "DynamicLoader.hxx.in"
#endif
// This file actually contains several different implementations:
// * NOOP for environments without dynamic libs
// * HP machines which uses shl_load
// * Mac OS X 10.2.x and earlier which uses NSLinkModule
// * Windows which uses LoadLibrary
// * BeOS / Haiku
// * FreeMiNT for Atari
// * Default implementation for *NIX systems (including Mac OS X 10.3 and
// later) which use dlopen
//
// Each part of the ifdef contains a complete implementation for
// the static methods of DynamicLoader.
#define CHECK_OPEN_FLAGS(var, supported, ret) \
do { \
/* Check for unknown flags. */ \
if ((var & AllOpenFlags) != var) { \
return ret; \
} \
\
/* Check for unsupported flags. */ \
if ((var & (supported)) != var) { \
return ret; \
} \
} while (0)
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname)
{
return DynamicLoader::OpenLibrary(libname, 0);
}
}
#if !KWSYS_SUPPORTS_SHARED_LIBS
// Implementation for environments without dynamic libs
# include <string.h> // for strerror()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname, int flags)
{
return 0;
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
if (!lib) {
return 0;
}
return 1;
}
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)
{
return 0;
}
const char* DynamicLoader::LastError()
{
return "General error";
}
} // namespace KWSYS_NAMESPACE
#elif defined(__hpux)
// Implementation for HPUX machines
# include <dl.h>
# include <errno.h>
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname, int flags)
{
CHECK_OPEN_FLAGS(flags, 0, 0);
return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
if (!lib) {
return 0;
}
return !shl_unload(lib);
}
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)
{
void* addr;
int status;
/* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
* TYPE_DATA Look for a symbol in the data segment (for example,
* variables).
* TYPE_UNDEFINED Look for any symbol.
*/
status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
void* result = (status < 0) ? (void*)0 : addr;
// Hack to cast pointer-to-data to pointer-to-function.
return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
}
const char* DynamicLoader::LastError()
{
// TODO: Need implementation with errno/strerror
/* If successful, shl_findsym returns an integer (int) value zero. If
* shl_findsym cannot find sym, it returns -1 and sets errno to zero.
* If any other errors occur, shl_findsym returns -1 and sets errno to one
* of these values (defined in <errno.h>):
* ENOEXEC
* A format error was detected in the specified library.
* ENOSYM
* A symbol on which sym depends could not be found.
* EINVAL
* The specified handle is invalid.
*/
if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) {
return strerror(errno);
}
// else
return 0;
}
} // namespace KWSYS_NAMESPACE
#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030)
// Implementation for Mac OS X 10.2.x and earlier
# include <mach-o/dyld.h>
# include <string.h> // for strlen
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname, int flags)
{
CHECK_OPEN_FLAGS(flags, 0, 0);
NSObjectFileImageReturnCode rc;
NSObjectFileImage image = 0;
rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
// rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
if (rc != NSObjectFileImageSuccess) {
return 0;
}
NSModule handle = NSLinkModule(image, libname.c_str(),
NSLINKMODULE_OPTION_BINDNOW |
NSLINKMODULE_OPTION_RETURN_ON_ERROR);
NSDestroyObjectFileImage(image);
return handle;
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
// NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED
// With this option the memory for the module is not deallocated
// allowing pointers into the module to still be valid.
// You should use this option instead if your code experience some problems
// reported against Panther 10.3.9 (fixed in Tiger 10.4.2 and up)
bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE);
return success;
}
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)
{
void* result = 0;
// Need to prepend symbols with '_' on Apple-gcc compilers
std::string rsym = '_' + sym;
NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str());
if (symbol) {
result = NSAddressOfSymbol(symbol);
}
// Hack to cast pointer-to-data to pointer-to-function.
return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
}
const char* DynamicLoader::LastError()
{
return 0;
}
} // namespace KWSYS_NAMESPACE
#elif defined(_WIN32) && !defined(__CYGWIN__)
// Implementation for Windows win32 code but not cygwin
# include <windows.h>
# include <stdio.h>
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname, int flags)
{
CHECK_OPEN_FLAGS(flags, SearchBesideLibrary, nullptr);
DWORD llFlags = 0;
if (flags & SearchBesideLibrary) {
llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH;
}
return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(),
nullptr, llFlags);
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
return (int)FreeLibrary(lib);
}
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)
{
// TODO: The calling convention affects the name of the symbol. We
// should have a tool to help get the symbol with the desired
// calling convention. Currently we assume cdecl.
//
// Borland:
// __cdecl = "_func" (default)
// __fastcall = "@_func"
// __stdcall = "func"
//
// Watcom:
// __cdecl = "_func"
// __fastcall = "@_func@X"
// __stdcall = "_func@X"
// __watcall = "func_" (default)
//
// MSVC:
// __cdecl = "func" (default)
// __fastcall = "@_func@X"
// __stdcall = "_func@X"
//
// Note that the "@X" part of the name above is the total size (in
// bytes) of the arguments on the stack.
void* result;
# if defined(__BORLANDC__) || defined(__WATCOMC__)
// Need to prepend symbols with '_'
std::string ssym = '_' + sym;
const char* rsym = ssym.c_str();
# else
const char* rsym = sym.c_str();
# endif
result = (void*)GetProcAddress(lib, rsym);
// Hack to cast pointer-to-data to pointer-to-function.
# ifdef __WATCOMC__
return *(DynamicLoader::SymbolPointer*)(&result);
# else
return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
# endif
}
# define DYNLOAD_ERROR_BUFFER_SIZE 1024
const char* DynamicLoader::LastError()
{
wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1];
DWORD error = GetLastError();
DWORD length = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, nullptr);
static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1];
if (length < 1) {
/* FormatMessage failed. Use a default message. */
_snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
"DynamicLoader encountered error 0x%X. "
"FormatMessage failed with error 0x%X",
error, GetLastError());
return str;
}
if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str,
DYNLOAD_ERROR_BUFFER_SIZE, nullptr, nullptr)) {
/* WideCharToMultiByte failed. Use a default message. */
_snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
"DynamicLoader encountered error 0x%X. "
"WideCharToMultiByte failed with error 0x%X",
error, GetLastError());
}
return str;
}
} // namespace KWSYS_NAMESPACE
#elif defined(__BEOS__)
// Implementation for BeOS / Haiku
# include <string.h> // for strerror()
# include <be/kernel/image.h>
# include <be/support/Errors.h>
namespace KWSYS_NAMESPACE {
static image_id last_dynamic_err = B_OK;
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname, int flags)
{
CHECK_OPEN_FLAGS(flags, 0, 0);
// image_id's are integers, errors are negative. Add one just in case we
// get a valid image_id of zero (is that even possible?).
image_id rc = load_add_on(libname.c_str());
if (rc < 0) {
last_dynamic_err = rc;
return 0;
}
return rc + 1;
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
if (!lib) {
last_dynamic_err = B_BAD_VALUE;
return 0;
} else {
// The function dlclose() returns 0 on success, and non-zero on error.
status_t rc = unload_add_on(lib - 1);
if (rc != B_OK) {
last_dynamic_err = rc;
return 0;
}
}
return 1;
}
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)
{
// Hack to cast pointer-to-data to pointer-to-function.
union
{
void* pvoid;
DynamicLoader::SymbolPointer psym;
} result;
result.psym = nullptr;
if (!lib) {
last_dynamic_err = B_BAD_VALUE;
} else {
// !!! FIXME: BeOS can do function-only lookups...does this ever
// !!! FIXME: actually _want_ a data symbol lookup, or was this union
// !!! FIXME: a leftover of dlsym()? (s/ANY/TEXT for functions only).
status_t rc =
get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid);
if (rc != B_OK) {
last_dynamic_err = rc;
result.psym = nullptr;
}
}
return result.psym;
}
const char* DynamicLoader::LastError()
{
const char* retval = strerror(last_dynamic_err);
last_dynamic_err = B_OK;
return retval;
}
} // namespace KWSYS_NAMESPACE
#elif defined(__MINT__)
// Implementation for FreeMiNT on Atari
# define _GNU_SOURCE /* for program_invocation_name */
# include <dld.h>
# include <errno.h>
# include <malloc.h>
# include <string.h>
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname, int flags)
{
CHECK_OPEN_FLAGS(flags, 0, nullptr);
char* name = (char*)calloc(1, libname.size() + 1);
dld_init(program_invocation_name);
strncpy(name, libname.c_str(), libname.size());
dld_link(libname.c_str());
return (void*)name;
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
dld_unlink_by_file((char*)lib, 0);
free(lib);
return 0;
}
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)
{
// Hack to cast pointer-to-data to pointer-to-function.
union
{
void* pvoid;
DynamicLoader::SymbolPointer psym;
} result;
result.pvoid = dld_get_symbol(sym.c_str());
return result.psym;
}
const char* DynamicLoader::LastError()
{
return dld_strerror(dld_errno);
}
} // namespace KWSYS_NAMESPACE
#else
// Default implementation for *NIX systems (including Mac OS X 10.3 and
// later) which use dlopen
# include <dlfcn.h>
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
const std::string& libname, int flags)
{
CHECK_OPEN_FLAGS(flags, 0, nullptr);
return dlopen(libname.c_str(), RTLD_LAZY);
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
{
if (lib) {
// The function dlclose() returns 0 on success, and non-zero on error.
return !dlclose(lib);
}
// else
return 0;
}
DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
DynamicLoader::LibraryHandle lib, const std::string& sym)
{
// Hack to cast pointer-to-data to pointer-to-function.
union
{
void* pvoid;
DynamicLoader::SymbolPointer psym;
} result;
result.pvoid = dlsym(lib, sym.c_str());
return result.psym;
}
const char* DynamicLoader::LastError()
{
return dlerror();
}
} // namespace KWSYS_NAMESPACE
#endif
-106
View File
@@ -1,106 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_DynamicLoader_hxx
#define @KWSYS_NAMESPACE@_DynamicLoader_hxx
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <string>
#if defined(__hpux)
# include <dl.h>
#elif defined(_WIN32) && !defined(__CYGWIN__)
# include <windows.h>
#elif defined(__APPLE__)
# include <AvailabilityMacros.h>
# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
# include <mach-o/dyld.h>
# endif
#elif defined(__BEOS__)
# include <be/kernel/image.h>
#endif
namespace @KWSYS_NAMESPACE@ {
/** \class DynamicLoader
* \brief Portable loading of dynamic libraries or dll's.
*
* DynamicLoader provides a portable interface to loading dynamic
* libraries or dll's into a process.
*
* Directory currently works with Windows, Apple, HP-UX and Unix (POSIX)
* operating systems
*
* \warning dlopen on *nix system works the following way:
* If filename contains a slash ("/"), then it is interpreted as a (relative
* or absolute) pathname. Otherwise, the dynamic linker searches for the
* library as follows : see ld.so(8) for further details):
* Whereas this distinction does not exist on Win32. Therefore ideally you
* should be doing full path to guarantee 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)();
enum OpenFlags
{
// Search for dependent libraries beside the library being loaded.
//
// This is currently only supported on Windows.
SearchBesideLibrary = 0x00000001,
AllOpenFlags = SearchBesideLibrary
};
/** Load a dynamic library into the current process.
* The returned LibraryHandle can be used to access the symbols in the
* library. The optional second argument is a set of flags to use when
* opening the library. If unrecognized or unsupported flags are specified,
* the library is not opened. */
static LibraryHandle OpenLibrary(const std::string&);
static LibraryHandle OpenLibrary(const std::string&, int);
/** Attempt to detach a dynamic library from the
* process. A value of true is returned if it is successful. */
static int CloseLibrary(LibraryHandle);
/** Find the address of the symbol in the given library. */
static SymbolPointer GetSymbolAddress(LibraryHandle, const std::string&);
/** Return the default module prefix for the current platform. */
static const char* LibPrefix() { return "@KWSYS_DynamicLoader_PREFIX@"; }
/** Return the default module suffix for the current platform. */
static const char* LibExtension() { return "@KWSYS_DynamicLoader_SUFFIX@"; }
/** Return the last error produced from a calls made on this class. */
static const char* LastError();
}; // End Class: DynamicLoader
} // namespace @KWSYS_NAMESPACE@
#endif
-69
View File
@@ -1,69 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Encoding_h
#define @KWSYS_NAMESPACE@_Encoding_h
#include <@KWSYS_NAMESPACE@/Configure.h>
#include <wchar.h>
/* Redefine all public interface symbol names to be in the proper
namespace. These macros are used internally to kwsys only, and are
not visible to user code. Use kwsysHeaderDump.pl to reproduce
these macros after making changes to the interface. */
#if !defined(KWSYS_NAMESPACE)
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsysEncoding kwsys_ns(Encoding)
# define kwsysEncoding_mbstowcs kwsys_ns(Encoding_mbstowcs)
# define kwsysEncoding_DupToWide kwsys_ns(Encoding_DupToWide)
# define kwsysEncoding_wcstombs kwsys_ns(Encoding_wcstombs)
# define kwsysEncoding_DupToNarrow kwsys_ns(Encoding_DupToNarrow)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/* Convert a narrow string to a wide string.
On Windows, UTF-8 is assumed, and on other platforms,
the current locale is assumed.
*/
kwsysEXPORT size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* src,
size_t n);
/* Convert a narrow string to a wide string.
This can return NULL if the conversion fails. */
kwsysEXPORT wchar_t* kwsysEncoding_DupToWide(const char* src);
/* Convert a wide string to a narrow string.
On Windows, UTF-8 is assumed, and on other platforms,
the current locale is assumed. */
kwsysEXPORT size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* src,
size_t n);
/* Convert a wide string to a narrow string.
This can return NULL if the conversion fails. */
kwsysEXPORT char* kwsysEncoding_DupToNarrow(const wchar_t* str);
#if defined(__cplusplus)
} /* extern "C" */
#endif
/* If we are building a kwsys .c or .cxx file, let it use these macros.
Otherwise, undefine them to keep the namespace clean. */
#if !defined(KWSYS_NAMESPACE)
# undef kwsys_ns
# undef kwsysEXPORT
# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# undef kwsysEncoding
# undef kwsysEncoding_mbstowcs
# undef kwsysEncoding_DupToWide
# undef kwsysEncoding_wcstombs
# undef kwsysEncoding_DupToNarrow
# endif
#endif
#endif
-80
View File
@@ -1,80 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Encoding_hxx
#define @KWSYS_NAMESPACE@_Encoding_hxx
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <string>
#include <vector>
namespace @KWSYS_NAMESPACE@ {
class @KWSYS_NAMESPACE@_EXPORT Encoding
{
public:
// Container class for argc/argv.
class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments
{
public:
// On Windows, get the program command line arguments
// in this Encoding module's 8 bit encoding.
// On other platforms the given argc/argv is used, and
// to be consistent, should be the argc/argv from main().
static CommandLineArguments Main(int argc, char const* const* argv);
// Construct CommandLineArguments with the given
// argc/argv. It is assumed that the string is already
// in the encoding used by this module.
CommandLineArguments(int argc, char const* const* argv);
// Construct CommandLineArguments with the given
// argc and wide argv. This is useful if wmain() is used.
CommandLineArguments(int argc, wchar_t const* const* argv);
~CommandLineArguments();
CommandLineArguments(const CommandLineArguments&);
CommandLineArguments& operator=(const CommandLineArguments&);
int argc() const;
char const* const* argv() const;
protected:
std::vector<char*> argv_;
};
/**
* Convert between char and wchar_t
*/
#if @KWSYS_NAMESPACE@_STL_HAS_WSTRING
// Convert a narrow string to a wide string.
// On Windows, UTF-8 is assumed, and on other platforms,
// the current locale is assumed.
static std::wstring ToWide(const std::string& str);
static std::wstring ToWide(const char* str);
// Convert a wide string to a narrow string.
// On Windows, UTF-8 is assumed, and on other platforms,
// the current locale is assumed.
static std::string ToNarrow(const std::wstring& str);
static std::string ToNarrow(const wchar_t* str);
# if defined(_WIN32)
/**
* Convert the path to an extended length path to avoid MAX_PATH length
* limitations on Windows. If the input is a local path the result will be
* prefixed with \\?\; if the input is instead a network path, the result
* will be prefixed with \\?\UNC\. All output will also be converted to
* absolute paths with Windows-style backslashes.
**/
static std::wstring ToWindowsExtendedPath(std::string const&);
static std::wstring ToWindowsExtendedPath(const char* source);
static std::wstring ToWindowsExtendedPath(std::wstring const& wsource);
# endif
#endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING
}; // class Encoding
} // namespace @KWSYS_NAMESPACE@
#endif
-72
View File
@@ -1,72 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Encoding.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
#if 0
# include "Encoding.h.in"
#endif
#include <stdlib.h>
#ifdef _WIN32
# include <windows.h>
#endif
size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* str, size_t n)
{
if (str == 0) {
return (size_t)-1;
}
#ifdef _WIN32
return MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest,
(int)n) -
1;
#else
return mbstowcs(dest, str, n);
#endif
}
wchar_t* kwsysEncoding_DupToWide(const char* str)
{
wchar_t* ret = NULL;
size_t length = kwsysEncoding_mbstowcs(NULL, str, 0) + 1;
if (length > 0) {
ret = (wchar_t*)malloc((length) * sizeof(wchar_t));
if (ret) {
ret[0] = 0;
kwsysEncoding_mbstowcs(ret, str, length);
}
}
return ret;
}
size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* str, size_t n)
{
if (str == 0) {
return (size_t)-1;
}
#ifdef _WIN32
return WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest,
(int)n, NULL, NULL) -
1;
#else
return wcstombs(dest, str, n);
#endif
}
char* kwsysEncoding_DupToNarrow(const wchar_t* str)
{
char* ret = NULL;
size_t length = kwsysEncoding_wcstombs(0, str, 0) + 1;
if (length > 0) {
ret = (char*)malloc(length);
if (ret) {
ret[0] = 0;
kwsysEncoding_wcstombs(ret, str, length);
}
}
return ret;
}
-288
View File
@@ -1,288 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifdef __osf__
# define _OSF_SOURCE
# define _POSIX_C_SOURCE 199506L
# define _XOPEN_SOURCE_EXTENDED
#endif
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Encoding.hxx)
#include KWSYS_HEADER(Encoding.h)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Encoding.h.in"
# include "Encoding.hxx.in"
#endif
#include <stdlib.h>
#include <string.h>
#include <vector>
#ifdef _MSC_VER
# pragma warning(disable : 4786)
#endif
// Windows API.
#if defined(_WIN32)
# include <windows.h>
# include <ctype.h>
# include <shellapi.h>
#endif
namespace KWSYS_NAMESPACE {
Encoding::CommandLineArguments Encoding::CommandLineArguments::Main(
int argc, char const* const* argv)
{
#ifdef _WIN32
(void)argc;
(void)argv;
int ac;
LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &ac);
std::vector<std::string> av1(ac);
std::vector<char const*> av2(ac);
for (int i = 0; i < ac; i++) {
av1[i] = ToNarrow(w_av[i]);
av2[i] = av1[i].c_str();
}
LocalFree(w_av);
return CommandLineArguments(ac, &av2[0]);
#else
return CommandLineArguments(argc, argv);
#endif
}
Encoding::CommandLineArguments::CommandLineArguments(int ac,
char const* const* av)
{
this->argv_.resize(ac + 1);
for (int i = 0; i < ac; i++) {
this->argv_[i] = strdup(av[i]);
}
this->argv_[ac] = nullptr;
}
Encoding::CommandLineArguments::CommandLineArguments(int ac,
wchar_t const* const* av)
{
this->argv_.resize(ac + 1);
for (int i = 0; i < ac; i++) {
this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]);
}
this->argv_[ac] = nullptr;
}
Encoding::CommandLineArguments::~CommandLineArguments()
{
for (size_t i = 0; i < this->argv_.size(); i++) {
free(argv_[i]);
}
}
Encoding::CommandLineArguments::CommandLineArguments(
const CommandLineArguments& other)
{
this->argv_.resize(other.argv_.size());
for (size_t i = 0; i < this->argv_.size(); i++) {
this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr;
}
}
Encoding::CommandLineArguments& Encoding::CommandLineArguments::operator=(
const CommandLineArguments& other)
{
if (this != &other) {
size_t i;
for (i = 0; i < this->argv_.size(); i++) {
free(this->argv_[i]);
}
this->argv_.resize(other.argv_.size());
for (i = 0; i < this->argv_.size(); i++) {
this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr;
}
}
return *this;
}
int Encoding::CommandLineArguments::argc() const
{
return static_cast<int>(this->argv_.size() - 1);
}
char const* const* Encoding::CommandLineArguments::argv() const
{
return &this->argv_[0];
}
#if KWSYS_STL_HAS_WSTRING
std::wstring Encoding::ToWide(const std::string& str)
{
std::wstring wstr;
# if defined(_WIN32)
const int wlength =
MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
int(str.size()), nullptr, 0);
if (wlength > 0) {
wchar_t* wdata = new wchar_t[wlength];
int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
int(str.size()), wdata, wlength);
if (r > 0) {
wstr = std::wstring(wdata, wlength);
}
delete[] wdata;
}
# else
size_t pos = 0;
size_t nullPos = 0;
do {
if (pos < str.size() && str.at(pos) != '\0') {
wstr += ToWide(str.c_str() + pos);
}
nullPos = str.find('\0', pos);
if (nullPos != std::string::npos) {
pos = nullPos + 1;
wstr += wchar_t('\0');
}
} while (nullPos != std::string::npos);
# endif
return wstr;
}
std::string Encoding::ToNarrow(const std::wstring& str)
{
std::string nstr;
# if defined(_WIN32)
int length =
WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(),
int(str.size()), nullptr, 0, nullptr, nullptr);
if (length > 0) {
char* data = new char[length];
int r =
WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(),
int(str.size()), data, length, nullptr, nullptr);
if (r > 0) {
nstr = std::string(data, length);
}
delete[] data;
}
# else
size_t pos = 0;
size_t nullPos = 0;
do {
if (pos < str.size() && str.at(pos) != '\0') {
nstr += ToNarrow(str.c_str() + pos);
}
nullPos = str.find(wchar_t('\0'), pos);
if (nullPos != std::string::npos) {
pos = nullPos + 1;
nstr += '\0';
}
} while (nullPos != std::string::npos);
# endif
return nstr;
}
std::wstring Encoding::ToWide(const char* cstr)
{
std::wstring wstr;
size_t length = kwsysEncoding_mbstowcs(nullptr, cstr, 0) + 1;
if (length > 0) {
std::vector<wchar_t> wchars(length);
if (kwsysEncoding_mbstowcs(&wchars[0], cstr, length) > 0) {
wstr = &wchars[0];
}
}
return wstr;
}
std::string Encoding::ToNarrow(const wchar_t* wcstr)
{
std::string str;
size_t length = kwsysEncoding_wcstombs(nullptr, wcstr, 0) + 1;
if (length > 0) {
std::vector<char> chars(length);
if (kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0) {
str = &chars[0];
}
}
return str;
}
# if defined(_WIN32)
// Convert local paths to UNC style paths
std::wstring Encoding::ToWindowsExtendedPath(std::string const& source)
{
return ToWindowsExtendedPath(ToWide(source));
}
// Convert local paths to UNC style paths
std::wstring Encoding::ToWindowsExtendedPath(const char* source)
{
return ToWindowsExtendedPath(ToWide(source));
}
// Convert local paths to UNC style paths
std::wstring Encoding::ToWindowsExtendedPath(std::wstring const& wsource)
{
// Resolve any relative paths
DWORD wfull_len;
/* The +3 is a workaround for a bug in some versions of GetFullPathNameW that
* won't return a large enough buffer size if the input is too small */
wfull_len = GetFullPathNameW(wsource.c_str(), 0, nullptr, nullptr) + 3;
std::vector<wchar_t> wfull(wfull_len);
GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], nullptr);
/* This should get the correct size without any extra padding from the
* previous size workaround. */
wfull_len = static_cast<DWORD>(wcslen(&wfull[0]));
if (wfull_len >= 2 && isalpha(wfull[0]) &&
wfull[1] == L':') { /* C:\Foo\bar\FooBar.txt */
return L"\\\\?\\" + std::wstring(&wfull[0]);
} else if (wfull_len >= 2 && wfull[0] == L'\\' &&
wfull[1] == L'\\') { /* Starts with \\ */
if (wfull_len >= 4 && wfull[2] == L'?' &&
wfull[3] == L'\\') { /* Starts with \\?\ */
if (wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' &&
wfull[6] == L'C' &&
wfull[7] == L'\\') { /* \\?\UNC\Foo\bar\FooBar.txt */
return std::wstring(&wfull[0]);
} else if (wfull_len >= 6 && isalpha(wfull[4]) &&
wfull[5] == L':') { /* \\?\C:\Foo\bar\FooBar.txt */
return std::wstring(&wfull[0]);
} else if (wfull_len >= 5) { /* \\?\Foo\bar\FooBar.txt */
return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]);
}
} else if (wfull_len >= 4 && wfull[2] == L'.' &&
wfull[3] == L'\\') { /* Starts with \\.\ a device name */
if (wfull_len >= 6 && isalpha(wfull[4]) &&
wfull[5] == L':') { /* \\.\C:\Foo\bar\FooBar.txt */
return L"\\\\?\\" + std::wstring(&wfull[4]);
} else if (wfull_len >=
5) { /* \\.\Foo\bar\ Device name is left unchanged */
return std::wstring(&wfull[0]);
}
} else if (wfull_len >= 3) { /* \\Foo\bar\FooBar.txt */
return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]);
}
}
// If this case has been reached, then the path is invalid. Leave it
// unchanged
return wsource;
}
# endif
#endif // KWSYS_STL_HAS_WSTRING
} // namespace KWSYS_NAMESPACE
-1
View File
@@ -1 +0,0 @@
MESSAGE("*** This message is generated by message inside a file that is included in DartTestfile.txt ***")
-55
View File
@@ -1,55 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(FStream.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "FStream.hxx.in"
#endif
namespace KWSYS_NAMESPACE {
namespace FStream {
BOM ReadBOM(std::istream& in)
{
if (!in.good()) {
return BOM_None;
}
unsigned long orig = in.tellg();
unsigned char bom[4];
in.read(reinterpret_cast<char*>(bom), 2);
if (!in.good()) {
in.clear();
in.seekg(orig);
return BOM_None;
}
if (bom[0] == 0xEF && bom[1] == 0xBB) {
in.read(reinterpret_cast<char*>(bom + 2), 1);
if (in.good() && bom[2] == 0xBF) {
return BOM_UTF8;
}
} else if (bom[0] == 0xFE && bom[1] == 0xFF) {
return BOM_UTF16BE;
} else if (bom[0] == 0x00 && bom[1] == 0x00) {
in.read(reinterpret_cast<char*>(bom + 2), 2);
if (in.good() && bom[2] == 0xFE && bom[3] == 0xFF) {
return BOM_UTF32BE;
}
} else if (bom[0] == 0xFF && bom[1] == 0xFE) {
unsigned long p = in.tellg();
in.read(reinterpret_cast<char*>(bom + 2), 2);
if (in.good() && bom[2] == 0x00 && bom[3] == 0x00) {
return BOM_UTF32LE;
}
in.seekg(p);
return BOM_UTF16LE;
}
in.clear();
in.seekg(orig);
return BOM_None;
}
} // FStream namespace
} // KWSYS_NAMESPACE
-278
View File
@@ -1,278 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_FStream_hxx
#define @KWSYS_NAMESPACE@_FStream_hxx
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <@KWSYS_NAMESPACE@/Encoding.hxx>
#include <fstream>
#if defined(_WIN32)
# if !defined(_MSC_VER) && @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H
# include <ext/stdio_filebuf.h>
# endif
#endif
namespace @KWSYS_NAMESPACE@ {
#if defined(_WIN32) && \
(defined(_MSC_VER) || @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H)
# if defined(_NOEXCEPT)
# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT _NOEXCEPT
# else
# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT
# endif
# if defined(_MSC_VER)
template <typename CharType, typename Traits>
class basic_filebuf : public std::basic_filebuf<CharType, Traits>
{
# if _MSC_VER >= 1400
public:
typedef std::basic_filebuf<CharType, Traits> my_base_type;
basic_filebuf* open(char const* s, std::ios_base::openmode mode)
{
const std::wstring wstr = Encoding::ToWindowsExtendedPath(s);
return static_cast<basic_filebuf*>(my_base_type::open(wstr.c_str(), mode));
}
# endif
};
# else
inline std::wstring getcmode(const std::ios_base::openmode mode)
{
std::wstring cmode;
bool plus = false;
if (mode & std::ios_base::app) {
cmode += L"a";
plus = mode & std::ios_base::in ? true : false;
} else if (mode & std::ios_base::trunc ||
(mode & std::ios_base::out && (mode & std::ios_base::in) == 0)) {
cmode += L"w";
plus = mode & std::ios_base::in ? true : false;
} else {
cmode += L"r";
plus = mode & std::ios_base::out ? true : false;
}
if (plus) {
cmode += L"+";
}
if (mode & std::ios_base::binary) {
cmode += L"b";
} else {
cmode += L"t";
}
return cmode;
};
# endif
template <typename CharType, typename Traits = std::char_traits<CharType> >
class basic_efilebuf
{
public:
# if defined(_MSC_VER)
typedef basic_filebuf<CharType, Traits> internal_buffer_type;
# else
typedef __gnu_cxx::stdio_filebuf<CharType, Traits> internal_buffer_type;
# endif
basic_efilebuf()
: file_(0)
{
buf_ = 0;
}
bool _open(char const* file_name, std::ios_base::openmode mode)
{
if (is_open() || file_) {
return false;
}
# if defined(_MSC_VER)
const bool success = buf_->open(file_name, mode) != 0;
# else
const std::wstring wstr = Encoding::ToWindowsExtendedPath(file_name);
bool success = false;
std::wstring cmode = getcmode(mode);
file_ = _wfopen(wstr.c_str(), cmode.c_str());
if (file_) {
if (buf_) {
delete buf_;
}
buf_ = new internal_buffer_type(file_, mode);
success = true;
}
# endif
return success;
}
bool is_open()
{
if (!buf_) {
return false;
}
return buf_->is_open();
}
bool is_open() const
{
if (!buf_) {
return false;
}
return buf_->is_open();
}
bool _close()
{
bool success = false;
if (buf_) {
success = buf_->close() != 0;
# if !defined(_MSC_VER)
if (file_) {
success = fclose(file_) == 0 ? success : false;
file_ = 0;
}
# endif
}
return success;
}
static void _set_state(bool success, std::basic_ios<CharType, Traits>* ios,
basic_efilebuf* efilebuf)
{
# if !defined(_MSC_VER)
ios->rdbuf(efilebuf->buf_);
# else
static_cast<void>(efilebuf);
# endif
if (!success) {
ios->setstate(std::ios_base::failbit);
} else {
ios->clear();
}
}
~basic_efilebuf()
{
if (buf_) {
delete buf_;
}
}
protected:
internal_buffer_type* buf_;
FILE* file_;
};
template <typename CharType, typename Traits = std::char_traits<CharType> >
class basic_ifstream
: public std::basic_istream<CharType, Traits>
, public basic_efilebuf<CharType, Traits>
{
public:
typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type
internal_buffer_type;
typedef std::basic_istream<CharType, Traits> internal_stream_type;
basic_ifstream()
: internal_stream_type(new internal_buffer_type())
{
this->buf_ =
static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
}
explicit basic_ifstream(char const* file_name,
std::ios_base::openmode mode = std::ios_base::in)
: internal_stream_type(new internal_buffer_type())
{
this->buf_ =
static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
open(file_name, mode);
}
void open(char const* file_name,
std::ios_base::openmode mode = std::ios_base::in)
{
mode = mode | std::ios_base::in;
this->_set_state(this->_open(file_name, mode), this, this);
}
void close() { this->_set_state(this->_close(), this, this); }
using basic_efilebuf<CharType, Traits>::is_open;
internal_buffer_type* rdbuf() const { return this->buf_; }
~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); }
};
template <typename CharType, typename Traits = std::char_traits<CharType> >
class basic_ofstream
: public std::basic_ostream<CharType, Traits>
, public basic_efilebuf<CharType, Traits>
{
using basic_efilebuf<CharType, Traits>::is_open;
public:
typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type
internal_buffer_type;
typedef std::basic_ostream<CharType, Traits> internal_stream_type;
basic_ofstream()
: internal_stream_type(new internal_buffer_type())
{
this->buf_ =
static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
}
explicit basic_ofstream(char const* file_name,
std::ios_base::openmode mode = std::ios_base::out)
: internal_stream_type(new internal_buffer_type())
{
this->buf_ =
static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
open(file_name, mode);
}
void open(char const* file_name,
std::ios_base::openmode mode = std::ios_base::out)
{
mode = mode | std::ios_base::out;
this->_set_state(this->_open(file_name, mode), this, this);
}
void close() { this->_set_state(this->_close(), this, this); }
internal_buffer_type* rdbuf() const { return this->buf_; }
~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); }
};
typedef basic_ifstream<char> ifstream;
typedef basic_ofstream<char> ofstream;
# undef @KWSYS_NAMESPACE@_FStream_NOEXCEPT
#else
using std::ofstream;
using std::ifstream;
#endif
namespace FStream {
enum BOM
{
BOM_None,
BOM_UTF8,
BOM_UTF16BE,
BOM_UTF16LE,
BOM_UTF32BE,
BOM_UTF32LE
};
// Read a BOM, if one exists.
// If a BOM exists, the stream is advanced to after the BOM.
// This function requires a seekable stream (but not a relative
// seekable stream).
@KWSYS_NAMESPACE@_EXPORT BOM ReadBOM(std::istream& in);
}
}
#endif
@@ -1,6 +0,0 @@
.git* export-ignore
config* eol=lf whitespace=indent-with-non-tab
git-* eol=lf whitespace=indent-with-non-tab
tips eol=lf whitespace=indent-with-non-tab
setup-* eol=lf whitespace=indent-with-non-tab
-202
View File
@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-5
View File
@@ -1,5 +0,0 @@
Kitware Local Git Setup Scripts
Copyright 2010-2012 Kitware, Inc.
This product includes software developed at Kitware, Inc.
(http://www.kitware.com/).
-87
View File
@@ -1,87 +0,0 @@
Kitware Local Git Setup Scripts
Introduction
------------
This is a collection of local Git development setup scripts meant for
inclusion in project source trees to aid their development workflow.
Project-specific information needed by the scripts may be configured
in a "config" file added next to them in the project.
Import
------
A project may import these scripts into their source tree by
initializing a subtree merge. Bring up a Git prompt and set the
current working directory inside a clone of the target project.
Fetch the "setup" branch from the GitSetup repository:
$ git fetch ../GitSetup setup:setup
Prepare to merge the branch but place the content in a subdirectory.
Any prefix (with trailing '/') may be chosen so long as it is used
consistently within a project through the rest of these instructions:
$ git merge -s ours --no-commit setup
$ git read-tree -u --prefix=Utilities/GitSetup/ setup
Commit the merge with an informative message:
$ git commit
------------------------------------------------------------------------
Merge branch 'setup'
Add Utilities/GitSetup/ directory using subtree merge from
the general GitSetup repository "setup" branch.
------------------------------------------------------------------------
Optionally add to the project ".gitattributes" file the line
/Utilities/GitSetup export-ignore
to exclude the GitSetup directory from inclusion by "git archive"
since it does not make sense in source tarballs.
Configuration
-------------
Read the "Project configuration instructions" comment in each script.
Add a "config" file next to the scripts with desired configuration
(optionally copy and modify "config.sample"). For example, to
configure the "setup-hooks" script:
$ git config -f Utilities/GitSetup/config hooks.url "$url"
where "$url" is the project repository publishing the "hooks" branch.
When finished, add and commit the configuration file:
$ git add Utilities/GitSetup/config
$ git commit
Update
------
A project may update these scripts from the GitSetup repository.
Bring up a Git prompt and set the current working directory inside a
clone of the target project. Fetch the "setup" branch from the
GitSetup repository:
$ git fetch ../GitSetup setup:setup
Merge the "setup" branch into the subtree:
$ git merge -X subtree=Utilities/GitSetup setup
where "Utilities/GitSetup" is the same prefix used during the import
setup, but without a trailing '/'.
License
-------
Distributed under the Apache License 2.0.
See LICENSE and NOTICE for details.
-4
View File
@@ -1,4 +0,0 @@
[hooks]
url = https://gitlab.kitware.com/utils/gitsetup.git
[upstream]
url = https://gitlab.kitware.com/utils/kwsys.git
@@ -1,32 +0,0 @@
# Kitware Local Git Setup Scripts - Sample Project Configuration
#
# Copy to "config" and edit as necessary.
[hooks]
url = http://public.kitware.com/GitSetup.git
#branch = hooks
[ssh]
host = public.kitware.com
key = id_git_public
request-url = https://www.kitware.com/Admin/SendPassword.cgi
[stage]
#url = git://public.kitware.com/stage/Project.git
#pushurl = git@public.kitware.com:stage/Project.git
[gerrit]
#project = Project
site = http://review.source.kitware.com
# pushurl placeholder "$username" is literal
pushurl = $username@review.source.kitware.com:Project
[upstream]
url = git://public.kitware.com/Project.git
[gitlab]
host = gitlab.kitware.com
group-path = group
group-name = Group
project-path = project
project-name = Project
@@ -1,74 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2015 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
USAGE="[<remote>] [--no-topic] [--dry-run] [--]"
OPTIONS_SPEC=
SUBDIRECTORY_OK=Yes
. "$(git --exec-path)/git-sh-setup"
#-----------------------------------------------------------------------------
remote=''
refspecs=''
no_topic=''
dry_run=''
# Parse the command line options.
while test $# != 0; do
case "$1" in
--no-topic) no_topic=1 ;;
--dry-run) dry_run=--dry-run ;;
--) shift; break ;;
-*) usage ;;
*) test -z "$remote" || usage ; remote="$1" ;;
esac
shift
done
test $# = 0 || usage
# Default remote.
test -n "$remote" || remote="gerrit"
if test -z "$no_topic"; then
# Identify and validate the topic branch name.
head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic=''
if test -z "$topic" -o "$topic" = "master"; then
die 'Please name your topic:
git checkout -b descriptive-name'
fi
# The topic branch will be pushed by name.
refspecs="HEAD:refs/for/master/$topic $refspecs"
fi
# Fetch the current upstream master branch head.
# This helps computation of a minimal pack to push.
echo "Fetching $remote master"
fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out"
# Exit early if we have nothing to push.
if test -z "$refspecs"; then
echo 'Nothing to push!'
exit 0
fi
# Push. Save output and exit code.
echo "Pushing to $remote"
push_stdout=$(git push --porcelain $dry_run "$remote" $refspecs); push_exit=$?
echo "$push_stdout"
# Reproduce the push exit code.
exit $push_exit
@@ -1,177 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2015 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
USAGE='[<remote>] [<options>...] [--]
OPTIONS
--dry-run
Show what would be pushed without actually updating the destination
-f,--force
Force-push the topic HEAD to rewrite the destination branch
--no-default
Do not push the default branch (e.g. master)
--no-topic
Do not push the topic HEAD.
'
OPTIONS_SPEC=
SUBDIRECTORY_OK=Yes
. "$(git --exec-path)/git-sh-setup"
egrep-q() {
egrep "$@" >/dev/null 2>/dev/null
}
# Load the project configuration.
gitlab_upstream='' &&
gitlab_configured='' &&
config="${BASH_SOURCE%/*}/config" &&
protocol=$(git config -f "$config" --get gitlab.protocol ||
echo "https") &&
host=$(git config -f "$config" --get gitlab.host) &&
site=$(git config -f "$config" --get gitlab.site ||
echo "$protocol://$host") &&
group_path=$(git config -f "$config" --get gitlab.group-path) &&
project_path=$(git config -f "$config" --get gitlab.project-path) &&
gitlab_upstream="$site/$group_path/$project_path.git" &&
gitlab_pushurl=$(git config --get remote.gitlab.pushurl ||
git config --get remote.gitlab.url) &&
gitlab_configured=1
#-----------------------------------------------------------------------------
remote=''
refspecs=''
force=''
lease=false
lease_flag=''
no_topic=''
no_default=''
dry_run=''
# Parse the command line options.
while test $# != 0; do
case "$1" in
-f|--force) force='+'; lease=true ;;
--no-topic) no_topic=1 ;;
--dry-run) dry_run=--dry-run ;;
--no-default) no_default=1 ;;
--) shift; break ;;
-*) usage ;;
*) test -z "$remote" || usage ; remote="$1" ;;
esac
shift
done
test $# = 0 || usage
# Default remote.
test -n "$remote" || remote="gitlab"
if test -z "$no_topic"; then
# Identify and validate the topic branch name.
head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic=''
if test -z "$topic" -o "$topic" = "master"; then
die 'Please name your topic:
git checkout -b descriptive-name'
fi
if $lease; then
have_ref=false
remoteref="refs/remotes/$remote/$topic"
if git rev-parse --verify -q "$remoteref"; then
have_ref=true
else
die "It seems that a local ref for the branch is
missing; forcing a push is dangerous and may overwrite
previous work. Fetch from the $remote remote first or
push without '-f' or '--force'."
fi
have_lease_flag=false
if git push -h | egrep-q -e '--force-with-lease'; then
have_lease_flag=true
fi
if $have_lease_flag && $have_ref; then
# Set the lease flag.
lease_flag="--force-with-lease=$topic:$remoteref"
# Clear the force string.
force=''
fi
fi
# The topic branch will be pushed by name.
refspecs="${force}HEAD:refs/heads/$topic $refspecs"
fi
# Fetch the current remote master branch head.
# This helps computation of a minimal pack to push.
echo "Fetching $remote master"
fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out"
gitlab_head=$(git rev-parse FETCH_HEAD) || exit
# Fetch the current upstream master branch head.
if origin_fetchurl=$(git config --get remote.origin.url) &&
test "$origin_fetchurl" = "$gitlab_upstream"; then
upstream_remote='origin'
else
upstream_remote="$gitlab_upstream"
fi
echo "Fetching $upstream_remote master"
fetch_out=$(git fetch "$upstream_remote" master 2>&1) || die "$fetch_out"
upstream_head=$(git rev-parse FETCH_HEAD) || exit
# Add a refspec to keep the remote master up to date if possible.
if test -z "$no_default" &&
base=$(git merge-base "$gitlab_head" "$upstream_head") &&
test "$base" = "$gitlab_head"; then
refspecs="$upstream_head:refs/heads/master $refspecs"
fi
# Exit early if we have nothing to push.
if test -z "$refspecs"; then
echo 'Nothing to push!'
exit 0
fi
# Push. Save output and exit code.
echo "Pushing to $remote"
push_config='-c advice.pushUpdateRejected=false'
push_stdout=$(git $push_config push $lease_flag --porcelain $dry_run "$remote" $refspecs); push_exit=$?
echo "$push_stdout"
if test "$push_exit" -ne 0 && test -z "$force"; then
# Advise the user to fetch if needed.
if echo "$push_stdout" | egrep-q 'stale info'; then
echo "
You have pushed to your branch from another machine; you may be overwriting
commits unintentionally. Fetch from the $remote remote and check that you are
not pushing an outdated branch."
fi
# Advise the user to force-push if needed.
if echo "$push_stdout" | egrep-q 'non-fast-forward'; then
echo '
Add "-f" or "--force" to push a rewritten topic.'
fi
fi
# Reproduce the push exit code.
exit $push_exit
-26
View File
@@ -1,26 +0,0 @@
#!/usr/bin/env bash
egrep-q() {
egrep "$@" >/dev/null 2>/dev/null
}
die() {
echo 'pre-commit hook failure' 1>&2
echo '-----------------------' 1>&2
echo '' 1>&2
echo "$@" 1>&2
exit 1
}
#-----------------------------------------------------------------------------
# Check that developmer setup is up-to-date.
lastSetupForDevelopment=$(git config --get hooks.SetupForDevelopment || echo 0)
eval $(grep '^SetupForDevelopment_VERSION=' "${BASH_SOURCE%/*}/../SetupForDevelopment.sh")
test -n "$SetupForDevelopment_VERSION" || SetupForDevelopment_VERSION=0
if test $lastSetupForDevelopment -lt $SetupForDevelopment_VERSION; then
die 'Developer setup in this work tree is out of date. Please re-run
./SetupForDevelopment.sh
'
fi
@@ -1,6 +0,0 @@
#!/usr/bin/env bash
echo "Adding 'git prepush' alias" &&
git config alias.prepush 'log --graph --stat origin/master..' &&
gerrit_disabled="KWSys no longer uses Gerrit. Please use GitLab." &&
git config alias.gerrit-push '!sh -c "echo '"${gerrit_disabled}"'"' &&
true
-147
View File
@@ -1,147 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2012 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
# Run this script to set up the local Git repository to push to
# a Gerrit Code Review instance for this project.
# Project configuration instructions:
#
# - Run a Gerrit Code Review server
#
# - Populate adjacent "config" file with:
# gerrit.site = Top Gerrit URL (not project-specific)
# gerrit.project = Name of project in Gerrit
# gerrit.pushurl = Review site push URL with "$username" placeholder
# gerrit.remote = Gerrit remote name, if not "gerrit"
# gerrit.url = Gerrit project URL, if not "$site/p/$project"
# optionally with "$username" placeholder
die() {
echo 1>&2 "$@" ; exit 1
}
# Make sure we are inside the repository.
cd "${BASH_SOURCE%/*}" &&
# Load the project configuration.
site=$(git config -f config --get gerrit.site) &&
project=$(git config -f config --get gerrit.project) &&
remote=$(git config -f config --get gerrit.remote ||
echo "gerrit") &&
fetchurl_=$(git config -f config --get gerrit.url ||
echo "$site/p/$project") &&
pushurl_=$(git config -f config --get gerrit.pushurl ||
git config -f config --get gerrit.url) ||
die 'This project is not configured to use Gerrit.'
# Get current gerrit push URL.
pushurl=$(git config --get remote."$remote".pushurl ||
git config --get remote."$remote".url || echo '') &&
# Tell user about current configuration.
if test -n "$pushurl"; then
echo 'Remote "'"$remote"'" is currently configured to push to
'"$pushurl"'
' &&
read -ep 'Reconfigure Gerrit? [y/N]: ' ans &&
if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
setup=1
else
setup=''
fi
else
echo 'Remote "'"$remote"'" is not yet configured.
'"$project"' changes must be pushed to our Gerrit Code Review site:
'"$site/p/$project"'
Register a Gerrit account and select a username (used below).
You will need an OpenID:
http://openid.net/get-an-openid/
' &&
read -ep 'Configure Gerrit? [Y/n]: ' ans &&
if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then
exit 0
else
setup=1
fi
fi &&
# Perform setup if necessary.
if test -n "$setup"; then
echo 'Sign-in to Gerrit to get/set your username at
'"$site"'/#/settings
Add your SSH public keys at
'"$site"'/#/settings/ssh-keys
' &&
read -ep "Gerrit username? [$USER]: " gu &&
if test -z "$gu"; then
gu="$USER"
fi &&
fetchurl="${fetchurl_/\$username/$gu}" &&
if test -z "$pushurl"; then
git remote add "$remote" "$fetchurl"
else
git config remote."$remote".url "$fetchurl"
fi &&
pushurl="${pushurl_/\$username/$gu}" &&
if test "$pushurl" != "$fetchurl"; then
git config remote."$remote".pushurl "$pushurl"
fi &&
echo 'Remote "'"$remote"'" is now configured to push to
'"$pushurl"'
'
fi &&
# Optionally test Gerrit access.
if test -n "$pushurl"; then
read -ep 'Test access to Gerrit (SSH)? [y/N]: ' ans &&
if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
echo -n 'Testing Gerrit access by SSH...'
if git ls-remote --heads "$pushurl" >/dev/null; then
echo 'passed.'
else
echo 'failed.' &&
die 'Could not access Gerrit. Add your SSH public keys at
'"$site"'/#/settings/ssh-keys
'
fi
fi
fi &&
# Set up GerritId hook.
hook=$(git config --get hooks.GerritId || echo '') &&
if test -z "$hook"; then
echo '
Enabling GerritId hook to add a "Change-Id" footer to commit
messages for interaction with Gerrit. Run
git config hooks.GerritId false
to disable this feature (but you will be on your own).' &&
git config hooks.GerritId true
else
echo 'GerritId hook already configured to "'"$hook"'".'
fi
-140
View File
@@ -1,140 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2015 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
# Run this script to set up the local Git repository to push to
# a personal fork for this project in GitLab.
# Project configuration instructions:
#
# - Run a GitLab server
#
# - Populate adjacent "config" file with:
# gitlab.protocol = Top GitLab protocol, if not 'https'
# gitlab.host = Top GitLab fully qualified host name
# gitlab.site = Top GitLab URL, if not "<protocol>://<host>"
# gitlab.group-name = Name of group containing project in GitLab
# gitlab.group-path = Path of group containing project in GitLab
# gitlab.project-name = Name of project within GitLab group
# gitlab.project-path = Path of project within GitLab group
# gitlab.url = GitLab push URL with "$username" placeholder,
# if not "<site>/$username/<project-path>.git"
# gitlab.pushurl = GitLab push URL with "$username" placeholder,
# if not "git@<host>:$username/<project-path>.git"
# gitlab.remote = GitLab remote name, if not "gitlab"
die() {
echo 1>&2 "$@" ; exit 1
}
# Make sure we are inside the repository.
cd "${BASH_SOURCE%/*}" &&
# Load the project configuration.
protocol=$(git config -f config --get gitlab.protocol ||
echo "https") &&
host=$(git config -f config --get gitlab.host) &&
site=$(git config -f config --get gitlab.site ||
echo "$protocol://$host") &&
group_path=$(git config -f config --get gitlab.group-path) &&
group_name=$(git config -f config --get gitlab.group-name) &&
project_name=$(git config -f config --get gitlab.project-name) &&
project_path=$(git config -f config --get gitlab.project-path) &&
pushurl_=$(git config -f config --get gitlab.pushurl ||
echo "git@$host:\$username/$project_path.git") &&
remote=$(git config -f config --get gitlab.remote ||
echo "gitlab") &&
fetchurl_=$(git config -f config --get gitlab.url ||
echo "$site/\$username/$project_path.git") ||
die 'This project is not configured to use GitLab.'
# Get current gitlab push URL.
pushurl=$(git config --get remote."$remote".pushurl ||
git config --get remote."$remote".url || echo '') &&
# Tell user about current configuration.
if test -n "$pushurl"; then
echo 'Remote "'"$remote"'" is currently configured to push to
'"$pushurl"'
' &&
read -ep 'Reconfigure GitLab? [y/N]: ' ans &&
if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
setup=1
else
setup=''
fi
else
echo 'Remote "'"$remote"'" is not yet configured.
' &&
read -ep 'Configure GitLab to contribute to '"$project_name"'? [Y/n]: ' ans &&
if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then
exit 0
else
setup=1
fi
fi &&
setup_instructions='Add your SSH public keys at
'"$site"'/profile/keys
Then visit the main repository at:
'"$site/$group_path/$project_path"'
and use the Fork button in the upper right.
'
# Perform setup if necessary.
if test -n "$setup"; then
echo 'Sign-in to GitLab to get/set your username at
'"$site/profile/account"'
'"$setup_instructions" &&
read -ep "GitLab username? [$USER]: " gu &&
if test -z "$gu"; then
gu="$USER"
fi &&
fetchurl="${fetchurl_/\$username/$gu}" &&
if test -z "$pushurl"; then
git remote add "$remote" "$fetchurl"
else
git config remote."$remote".url "$fetchurl"
fi &&
pushurl="${pushurl_/\$username/$gu}" &&
git config remote."$remote".pushurl "$pushurl" &&
echo 'Remote "'"$remote"'" is now configured to push to
'"$pushurl"'
'
fi &&
# Optionally test GitLab access.
if test -n "$pushurl"; then
read -ep 'Test access to GitLab (SSH)? [y/N]: ' ans &&
if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
echo -n 'Testing GitLab access by SSH...'
if git ls-remote --heads "$pushurl" >/dev/null; then
echo 'passed.'
else
echo 'failed.' &&
die 'Could not access your GitLab fork of this project.
'"$setup_instructions"
fi
fi
fi
@@ -1,64 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2012 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
# Run this script to set up local Git hooks for this project.
# Project configuration instructions:
#
# - Publish a "hooks" branch in the project repository such that
# clones will have "refs/remotes/origin/hooks".
#
# - Populate adjacent "config" file with:
# hooks.url = Repository URL publishing "hooks" branch
# hooks.branch = Repository branch instead of "hooks"
egrep-q() {
egrep "$@" >/dev/null 2>/dev/null
}
die() {
echo 1>&2 "$@" ; exit 1
}
# Make sure we are inside the repository.
cd "${BASH_SOURCE%/*}" &&
# Select a hooks branch.
if url=$(git config --get hooks.url); then
# Fetch hooks from locally configured repository.
branch=$(git config hooks.branch || echo hooks)
elif git for-each-ref refs/remotes/origin/hooks 2>/dev/null |
egrep-q 'refs/remotes/origin/hooks$'; then
# Use hooks cloned from origin.
url=.. && branch=remotes/origin/hooks
elif url=$(git config -f config --get hooks.url); then
# Fetch hooks from project-configured repository.
branch=$(git config -f config hooks.branch || echo hooks)
else
die 'This project is not configured to install local hooks.'
fi &&
# Populate ".git/hooks".
echo 'Setting up git hooks...' &&
git_dir=$(git rev-parse --git-dir) &&
mkdir -p "$git_dir/hooks" &&
cd "$git_dir/hooks" &&
if ! test -e .git; then
git init -q || die 'Could not run git init for hooks.'
fi &&
git fetch -q "$url" "$branch" &&
git reset -q --hard FETCH_HEAD || die 'Failed to install hooks'
-111
View File
@@ -1,111 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2012 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
# Run this script to set up ssh push access to the repository host.
# Project configuration instructions:
#
# - Populate adjacent "config" file with:
# ssh.host = Repository host name
# ssh.user = Username on host, if not "git"
# ssh.key = Local ssh key name
# ssh.request-url = Web page URL to request ssh access
egrep-q() {
egrep "$@" >/dev/null 2>/dev/null
}
die() {
echo 1>&2 "$@" ; exit 1
}
# Make sure we are inside the repository.
cd "${BASH_SOURCE%/*}" &&
# Load the project configuration.
host=$(git config -f config --get ssh.host) &&
user=$(git config -f config --get ssh.user || echo git) &&
key=$(git config -f config --get ssh.key) &&
request_url=$(git config -f config --get ssh.request-url) ||
die 'This project is not configured for ssh push access.'
# Check for existing configuration.
if test -r ~/.ssh/config &&
egrep-q 'Host[= ]'"${host//\./\\.}" ~/.ssh/config; then
echo 'Host "'"$host"'" is already in ~/.ssh/config' &&
setup= &&
question='Test'
else
echo 'Host "'"$host"'" not found in ~/.ssh/config' &&
setup=1 &&
question='Setup and test'
fi &&
# Ask the user whether to make changes.
echo '' &&
read -ep "${question} push access by ssh to $user@$host? [y/N]: " access &&
if test "$access" != "y" -a "$access" != "Y"; then
exit 0
fi &&
# Setup host configuration if necessary.
if test -n "$setup"; then
if ! test -d ~/.ssh; then
mkdir -p ~/.ssh &&
chmod 700 ~/.ssh
fi &&
if ! test -f ~/.ssh/config; then
touch ~/.ssh/config &&
chmod 600 ~/.ssh/config
fi &&
ssh_config='Host='"$host"'
IdentityFile ~/.ssh/'"$key" &&
echo "Adding to ~/.ssh/config:
$ssh_config
" &&
echo "$ssh_config" >> ~/.ssh/config &&
if ! test -e ~/.ssh/"$key"; then
if test -f ~/.ssh/id_rsa; then
# Take care of the common case.
ln -s id_rsa ~/.ssh/"$key"
echo '
Assuming ~/.ssh/id_rsa is the private key corresponding to the public key for
'"$user@$host"'
If this is incorrect place private key at "~/.ssh/'"$key"'".'
else
echo '
Place the private key corresponding to the public key registered for
'"$user@$host"'
at "~/.ssh/'"$key"'".'
fi
read -e -n 1 -p 'Press any key to continue...'
fi
fi || exit 1
# Test access configuration.
echo 'Testing ssh push access to "'"$user@$host"'"...' &&
if ! ssh "$user@$host" info; then
die 'No ssh push access to "'"$user@$host"'". You may need to request access at
'"$request_url"'
'
fi
@@ -1,82 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2012 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
# Run this script to set up the topic stage for pushing changes.
# Project configuration instructions:
#
# - Run a Topic Stage repository next to the main project repository.
#
# - Populate adjacent "config" file with:
# stage.url = Topic Stage repository URL
# stage.pushurl = Topic Stage push URL if not "$url"
egrep-q() {
egrep "$@" >/dev/null 2>/dev/null
}
die() {
echo 1>&2 "$@" ; exit 1
}
# Make sure we are inside the repository.
cd "${BASH_SOURCE%/*}" &&
# Load the project configuration.
fetchurl_=$(git config -f config --get stage.url) &&
pushurl_=$(git config -f config --get stage.pushurl || echo "$fetchurl_") &&
remote=$(git config -f config --get stage.remote || echo 'stage') ||
die 'This project is not configured to use a topic stage.'
# Get current stage push URL.
pushurl=$(git config --get remote."$remote".pushurl ||
git config --get remote."$remote".url || echo '') &&
# Tell user about current configuration.
if test -n "$pushurl"; then
echo 'Remote "'"$remote"'" is currently configured to push to
'"$pushurl"'
' &&
read -ep 'Reconfigure Topic Stage? [y/N]: ' ans &&
if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
setup=1
else
setup=''
fi
else
setup=1
fi
# Perform setup if necessary.
if test -n "$setup"; then
echo 'Setting up the topic stage...' &&
fetchurl="${fetchurl_}" &&
if test -z "$pushurl"; then
git remote add "$remote" "$fetchurl"
else
git config remote."$remote".url "$fetchurl"
fi &&
pushurl="${pushurl_}" &&
if test "$pushurl" != "$fetchurl"; then
git config remote."$remote".pushurl "$pushurl"
fi &&
echo 'Remote "'"$remote"'" is now configured to push to
'"$pushurl"'
'
fi || die 'Could not configure the topic stage remote.'
@@ -1,104 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2015 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
# Run this script to set up the local Git repository to use the
# preferred upstream repository URLs.
# Project configuration instructions:
#
# - Populate adjacent "config" file with:
# upstream.url = Preferred fetch url for upstream remote
# upstream.remote = Preferred name for upstream remote, if not "origin"
die() {
echo 1>&2 "$@" ; exit 1
}
# Make sure we are inside the repository.
cd "${BASH_SOURCE%/*}" &&
# Load the project configuration.
url=$(git config -f config --get upstream.url) &&
remote=$(git config -f config --get upstream.remote ||
echo 'origin') ||
die 'This project is not configured to use a preferred upstream repository.'
# Get current upstream URLs.
fetchurl=$(git config --get remote."$remote".url || echo '') &&
pushurl=$(git config --get remote."$remote".pushurl || echo '') &&
if test "$fetchurl" = "$url"; then
echo 'Remote "'"$remote"'" already uses recommended upstream repository.'
exit 0
fi
upstream_recommend='
We recommended configuring the "'"$remote"'" remote to fetch from upstream at
'"$url"'
'
# Tell user about current configuration.
if test -n "$fetchurl"; then
echo 'Remote "'"$remote"'" is currently configured to fetch from
'"$fetchurl"'
' &&
if test -n "$pushurl"; then
echo 'and push to
'"$pushurl"
fi &&
echo "$upstream_recommend" &&
if test -n "$pushurl"; then
echo 'and to never push to it directly.
'
fi &&
read -ep 'Reconfigure "'"$remote"'" remote as recommended? [y/N]: ' ans &&
if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
setup=1
else
setup=''
fi
else
echo 'Remote "'"$remote"'" is not yet configured.' &&
echo "$upstream_recommend" &&
read -ep 'Configure "'"$remote"'" remote as recommended? [Y/n]: ' ans &&
if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then
exit 0
else
setup=1
fi
fi &&
# Perform setup if necessary.
if test -n "$setup"; then
if test -z "$fetchurl"; then
git remote add "$remote" "$url"
else
git config remote."$remote".url "$url" &&
if old=$(git config --get remote."$remote".pushurl); then
git config --unset remote."$remote".pushurl ||
echo 'Warning: failed to unset remote.'"$remote"'.pushurl'
fi
fi &&
echo 'Remote "'"$remote"'" is now configured to fetch from
'"$url"'
'
fi
-39
View File
@@ -1,39 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2012 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
# Run this script to configure Git user info in this repository.
# Project configuration instructions: NONE
for (( ; ; )); do
user_name=$(git config user.name || echo '') &&
user_email=$(git config user.email || echo '') &&
if test -n "$user_name" -a -n "$user_email"; then
echo 'Your commits will record as Author:
'"$user_name <$user_email>"'
' &&
read -ep 'Is the author name and email address above correct? [Y/n] ' correct &&
if test "$correct" != "n" -a "$correct" != "N"; then
break
fi
fi &&
read -ep 'Enter your full name e.g. "John Doe": ' name &&
read -ep 'Enter your email address e.g. "john@gmail.com": ' email &&
git config user.name "$name" &&
git config user.email "$email"
done
-55
View File
@@ -1,55 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2010-2012 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
# This script makes optional suggestions for working with Git.
# Project configuration instructions: NONE
egrep-q() {
egrep "$@" >/dev/null 2>/dev/null
}
# Suggest color configuration.
if test -z "$(git config --get color.ui)"; then
echo '
One may enable color output from Git commands with
git config --global color.ui auto
'
fi
# Suggest bash completion.
if ! bash -i -c 'echo $PS1' | egrep-q '__git_ps1'; then
echo '
A dynamic, informative Git shell prompt can be obtained by sourcing
the git bash-completion script in your "~/.bashrc". Set the PS1
environmental variable as suggested in the comments at the top of the
bash-completion script. You may need to install the bash-completion
package from your distribution to obtain it.
'
fi
# Suggest merge tool.
if test -z "$(git config --get merge.tool)"; then
echo '
One may configure Git to load a merge tool with
git config merge.tool <toolname>
See "git help mergetool" for more information.
'
fi
-448
View File
@@ -1,448 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Glob.hxx)
#include KWSYS_HEADER(Configure.hxx)
#include KWSYS_HEADER(RegularExpression.hxx)
#include KWSYS_HEADER(SystemTools.hxx)
#include KWSYS_HEADER(Directory.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Configure.hxx.in"
# include "Directory.hxx.in"
# include "Glob.hxx.in"
# include "RegularExpression.hxx.in"
# include "SystemTools.hxx.in"
#endif
#include <algorithm>
#include <string>
#include <vector>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
namespace KWSYS_NAMESPACE {
#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
// On Windows and Apple, no difference between lower and upper case
# define KWSYS_GLOB_CASE_INDEPENDENT
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
// Handle network paths
# define KWSYS_GLOB_SUPPORT_NETWORK_PATHS
#endif
class GlobInternals
{
public:
std::vector<std::string> Files;
std::vector<kwsys::RegularExpression> Expressions;
};
Glob::Glob()
{
this->Internals = new GlobInternals;
this->Recurse = false;
this->Relative = "";
this->RecurseThroughSymlinks = true;
// RecurseThroughSymlinks is true by default for backwards compatibility,
// not because it's a good idea...
this->FollowedSymlinkCount = 0;
// Keep separate variables for directory listing for back compatibility
this->ListDirs = true;
this->RecurseListDirs = false;
}
Glob::~Glob()
{
delete this->Internals;
}
std::vector<std::string>& Glob::GetFiles()
{
return this->Internals->Files;
}
std::string Glob::PatternToRegex(const std::string& pattern,
bool require_whole_string, bool preserve_case)
{
// Incrementally build the regular expression from the pattern.
std::string regex = require_whole_string ? "^" : "";
std::string::const_iterator pattern_first = pattern.begin();
std::string::const_iterator pattern_last = pattern.end();
for (std::string::const_iterator i = pattern_first; i != pattern_last; ++i) {
int c = *i;
if (c == '*') {
// A '*' (not between brackets) matches any string.
// We modify this to not match slashes since the original 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 original glob
// pattern documentation was meant for matching file name
// components separated by slashes.
regex += "[^/]";
} else if (c == '[') {
// Parse out the bracket expression. It begins just after the
// opening character.
std::string::const_iterator bracket_first = i + 1;
std::string::const_iterator bracket_last = bracket_first;
// The first character may be complementation '!' or '^'.
if (bracket_last != pattern_last &&
(*bracket_last == '!' || *bracket_last == '^')) {
++bracket_last;
}
// If the next character is a ']' it is included in the brackets
// because the bracket string may not be empty.
if (bracket_last != pattern_last && *bracket_last == ']') {
++bracket_last;
}
// Search for the closing ']'.
while (bracket_last != pattern_last && *bracket_last != ']') {
++bracket_last;
}
// Check whether we have a complete bracket string.
if (bracket_last == pattern_last) {
// The bracket string did not end, so it was opened simply by
// a '[' that is supposed to be matched literally.
regex += "\\[";
} else {
// Convert the bracket string to its regex equivalent.
std::string::const_iterator k = bracket_first;
// Open the regex block.
regex += "[";
// A regex range complement uses '^' instead of '!'.
if (k != bracket_last && *k == '!') {
regex += "^";
++k;
}
// Convert the remaining characters.
for (; k != bracket_last; ++k) {
// Backslashes must be escaped.
if (*k == '\\') {
regex += "\\";
}
// Store this character.
regex += *k;
}
// Close the regex block.
regex += "]";
// Jump to the end of the bracket string.
i = bracket_last;
}
} else {
// A single character matches itself.
int ch = c;
if (!(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
('0' <= ch && ch <= '9'))) {
// Escape the non-alphanumeric character.
regex += "\\";
}
#if defined(KWSYS_GLOB_CASE_INDEPENDENT)
else {
// On case-insensitive systems file names are converted to lower
// case before matching.
if (!preserve_case) {
ch = tolower(ch);
}
}
#endif
(void)preserve_case;
// Store the character.
regex.append(1, static_cast<char>(ch));
}
}
if (require_whole_string) {
regex += "$";
}
return regex;
}
bool Glob::RecurseDirectory(std::string::size_type start,
const std::string& dir, GlobMessages* messages)
{
kwsys::Directory d;
if (!d.Load(dir)) {
return true;
}
unsigned long cc;
std::string realname;
std::string fname;
for (cc = 0; cc < d.GetNumberOfFiles(); cc++) {
fname = d.GetFile(cc);
if (fname == "." || fname == "..") {
continue;
}
if (start == 0) {
realname = dir + fname;
} else {
realname = dir + "/" + fname;
}
#if defined(KWSYS_GLOB_CASE_INDEPENDENT)
// On Windows and Apple, no difference between lower and upper case
fname = kwsys::SystemTools::LowerCase(fname);
#endif
bool isDir = kwsys::SystemTools::FileIsDirectory(realname);
bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname);
if (isDir && (!isSymLink || this->RecurseThroughSymlinks)) {
if (isSymLink) {
++this->FollowedSymlinkCount;
std::string realPathErrorMessage;
std::string canonicalPath(
SystemTools::GetRealPath(dir, &realPathErrorMessage));
if (!realPathErrorMessage.empty()) {
if (messages) {
messages->push_back(
Message(Glob::error,
"Canonical path generation from path '" + dir +
"' failed! Reason: '" + realPathErrorMessage + "'"));
}
return false;
}
if (std::find(this->VisitedSymlinks.begin(),
this->VisitedSymlinks.end(),
canonicalPath) == this->VisitedSymlinks.end()) {
if (this->RecurseListDirs) {
// symlinks are treated as directories
this->AddFile(this->Internals->Files, realname);
}
this->VisitedSymlinks.push_back(canonicalPath);
if (!this->RecurseDirectory(start + 1, realname, messages)) {
this->VisitedSymlinks.pop_back();
return false;
}
this->VisitedSymlinks.pop_back();
}
// else we have already visited this symlink - prevent cyclic recursion
else if (messages) {
std::string message;
for (std::vector<std::string>::const_iterator pathIt =
std::find(this->VisitedSymlinks.begin(),
this->VisitedSymlinks.end(), canonicalPath);
pathIt != this->VisitedSymlinks.end(); ++pathIt) {
message += *pathIt + "\n";
}
message += canonicalPath + "/" + fname;
messages->push_back(Message(Glob::cyclicRecursion, message));
}
} else {
if (this->RecurseListDirs) {
this->AddFile(this->Internals->Files, realname);
}
if (!this->RecurseDirectory(start + 1, realname, messages)) {
return false;
}
}
} else {
if (!this->Internals->Expressions.empty() &&
this->Internals->Expressions.back().find(fname)) {
this->AddFile(this->Internals->Files, realname);
}
}
}
return true;
}
void Glob::ProcessDirectory(std::string::size_type start,
const std::string& dir, GlobMessages* messages)
{
// std::cout << "ProcessDirectory: " << dir << std::endl;
bool last = (start == this->Internals->Expressions.size() - 1);
if (last && this->Recurse) {
this->RecurseDirectory(start, dir, messages);
return;
}
if (start >= this->Internals->Expressions.size()) {
return;
}
kwsys::Directory d;
if (!d.Load(dir)) {
return;
}
unsigned long cc;
std::string realname;
std::string fname;
for (cc = 0; cc < d.GetNumberOfFiles(); cc++) {
fname = d.GetFile(cc);
if (fname == "." || fname == "..") {
continue;
}
if (start == 0) {
realname = dir + fname;
} else {
realname = dir + "/" + fname;
}
#if defined(KWSYS_GLOB_CASE_INDEPENDENT)
// On case-insensitive file systems convert to lower case for matching.
fname = kwsys::SystemTools::LowerCase(fname);
#endif
// std::cout << "Look at file: " << fname << std::endl;
// std::cout << "Match: "
// << this->Internals->TextExpressions[start].c_str() << std::endl;
// std::cout << "Real name: " << realname << std::endl;
if ((!last && !kwsys::SystemTools::FileIsDirectory(realname)) ||
(!this->ListDirs && last &&
kwsys::SystemTools::FileIsDirectory(realname))) {
continue;
}
if (this->Internals->Expressions[start].find(fname)) {
if (last) {
this->AddFile(this->Internals->Files, realname);
} else {
this->ProcessDirectory(start + 1, realname, messages);
}
}
}
}
bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages)
{
std::string cexpr;
std::string::size_type cc;
std::string expr = inexpr;
this->Internals->Expressions.clear();
this->Internals->Files.clear();
if (!kwsys::SystemTools::FileIsFullPath(expr)) {
expr = kwsys::SystemTools::GetCurrentWorkingDirectory();
expr += "/" + inexpr;
}
std::string fexpr = expr;
std::string::size_type skip = 0;
std::string::size_type last_slash = 0;
for (cc = 0; cc < expr.size(); cc++) {
if (cc > 0 && expr[cc] == '/' && expr[cc - 1] != '\\') {
last_slash = cc;
}
if (cc > 0 && (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') &&
expr[cc - 1] != '\\') {
break;
}
}
if (last_slash > 0) {
// std::cout << "I can skip: " << fexpr.substr(0, last_slash)
// << std::endl;
skip = last_slash;
}
if (skip == 0) {
#if defined(KWSYS_GLOB_SUPPORT_NETWORK_PATHS)
// Handle network paths
if (expr[0] == '/' && expr[1] == '/') {
int cnt = 0;
for (cc = 2; cc < expr.size(); cc++) {
if (expr[cc] == '/') {
cnt++;
if (cnt == 2) {
break;
}
}
}
skip = int(cc + 1);
} else
#endif
// Handle drive letters on Windows
if (expr[1] == ':' && expr[0] != '/') {
skip = 2;
}
}
if (skip > 0) {
expr = expr.substr(skip);
}
cexpr = "";
for (cc = 0; cc < expr.size(); cc++) {
int ch = expr[cc];
if (ch == '/') {
if (!cexpr.empty()) {
this->AddExpression(cexpr);
}
cexpr = "";
} else {
cexpr.append(1, static_cast<char>(ch));
}
}
if (!cexpr.empty()) {
this->AddExpression(cexpr);
}
// Handle network paths
if (skip > 0) {
this->ProcessDirectory(0, fexpr.substr(0, skip) + "/", messages);
} else {
this->ProcessDirectory(0, "/", messages);
}
return true;
}
void Glob::AddExpression(const std::string& expr)
{
this->Internals->Expressions.push_back(
kwsys::RegularExpression(this->PatternToRegex(expr)));
}
void Glob::SetRelative(const char* dir)
{
if (!dir) {
this->Relative = "";
return;
}
this->Relative = dir;
}
const char* Glob::GetRelative()
{
if (this->Relative.empty()) {
return nullptr;
}
return this->Relative.c_str();
}
void Glob::AddFile(std::vector<std::string>& files, const std::string& file)
{
if (!this->Relative.empty()) {
files.push_back(kwsys::SystemTools::RelativePath(this->Relative, file));
} else {
files.push_back(file);
}
}
} // namespace KWSYS_NAMESPACE
-134
View File
@@ -1,134 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Glob_hxx
#define @KWSYS_NAMESPACE@_Glob_hxx
#include <@KWSYS_NAMESPACE@/Configure.h>
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <string>
#include <vector>
namespace @KWSYS_NAMESPACE@ {
class GlobInternals;
/** \class Glob
* \brief Portable globbing searches.
*
* Globbing expressions are much simpler than regular
* expressions. This class will search for files using
* globbing expressions.
*
* Finds all files that match a given globbing expression.
*/
class @KWSYS_NAMESPACE@_EXPORT Glob
{
public:
enum MessageType
{
error,
cyclicRecursion
};
struct Message
{
MessageType type;
std::string content;
Message(MessageType t, const std::string& c)
: type(t)
, content(c)
{
}
~Message() = default;
Message(const Message& msg) = default;
Message& operator=(Message const& msg) = default;
};
typedef std::vector<Message> GlobMessages;
typedef std::vector<Message>::iterator GlobMessagesIterator;
public:
Glob();
~Glob();
//! Find all files that match the pattern.
bool FindFiles(const std::string& inexpr, GlobMessages* messages = nullptr);
//! Return the list of files that matched.
std::vector<std::string>& GetFiles();
//! Set recurse to true to match subdirectories.
void RecurseOn() { this->SetRecurse(true); }
void RecurseOff() { this->SetRecurse(false); }
void SetRecurse(bool i) { this->Recurse = i; }
bool GetRecurse() { return this->Recurse; }
//! Set recurse through symlinks to true if recursion should traverse the
// linked-to directories
void RecurseThroughSymlinksOn() { this->SetRecurseThroughSymlinks(true); }
void RecurseThroughSymlinksOff() { this->SetRecurseThroughSymlinks(false); }
void SetRecurseThroughSymlinks(bool i) { this->RecurseThroughSymlinks = i; }
bool GetRecurseThroughSymlinks() { return this->RecurseThroughSymlinks; }
//! Get the number of symlinks followed through recursion
unsigned int GetFollowedSymlinkCount() { return this->FollowedSymlinkCount; }
//! Set relative to true to only show relative path to files.
void SetRelative(const char* dir);
const char* GetRelative();
/** Convert the given globbing pattern to a regular expression.
There is no way to quote meta-characters. The
require_whole_string argument specifies whether the regex is
automatically surrounded by "^" and "$" to match the whole
string. This is on by default because patterns always match
whole strings, but may be disabled to support concatenating
expressions more easily (regex1|regex2|etc). */
static std::string PatternToRegex(const std::string& pattern,
bool require_whole_string = true,
bool preserve_case = false);
/** Getters and setters for enabling and disabling directory
listing in recursive and non recursive globbing mode.
If listing is enabled in recursive mode it also lists
directory symbolic links even if follow symlinks is enabled. */
void SetListDirs(bool list) { this->ListDirs = list; }
bool GetListDirs() const { return this->ListDirs; }
void SetRecurseListDirs(bool list) { this->RecurseListDirs = list; }
bool GetRecurseListDirs() const { return this->RecurseListDirs; }
protected:
//! Process directory
void ProcessDirectory(std::string::size_type start, const std::string& dir,
GlobMessages* messages);
//! Process last directory, but only when recurse flags is on. That is
// effectively like saying: /path/to/file/**/file
bool RecurseDirectory(std::string::size_type start, const std::string& dir,
GlobMessages* messages);
//! Add regular expression
void AddExpression(const std::string& expr);
//! Add a file to the list
void AddFile(std::vector<std::string>& files, const std::string& file);
GlobInternals* Internals;
bool Recurse;
std::string Relative;
bool RecurseThroughSymlinks;
unsigned int FollowedSymlinkCount;
std::vector<std::string> VisitedSymlinks;
bool ListDirs;
bool RecurseListDirs;
private:
Glob(const Glob&); // Not implemented.
void operator=(const Glob&); // Not implemented.
};
} // namespace @KWSYS_NAMESPACE@
#endif
-255
View File
@@ -1,255 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Configure.hxx)
// Include the streams library.
#include <iostream>
#include KWSYS_HEADER(IOStream.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Configure.hxx.in"
# include "IOStream.hxx.in"
#endif
// Implement the rest of this file only if it is needed.
#if KWSYS_IOS_NEED_OPERATORS_LL
# include <stdio.h> // sscanf, sprintf
# include <string.h> // memchr
# if defined(_MAX_INT_DIG)
# define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG
# else
# define KWSYS_IOS_INT64_MAX_DIG 32
# endif
namespace KWSYS_NAMESPACE {
// Scan an input stream for an integer value.
static int IOStreamScanStream(std::istream& is, char* buffer)
{
// Prepare to write to buffer.
char* out = buffer;
char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1;
// Look for leading sign.
if (is.peek() == '+') {
*out++ = '+';
is.ignore();
} else if (is.peek() == '-') {
*out++ = '-';
is.ignore();
}
// Determine the base. If not specified in the stream, try to
// detect it from the input. A leading 0x means hex, and a leading
// 0 alone means octal.
int base = 0;
int flags = is.flags() & std::ios_base::basefield;
if (flags == std::ios_base::oct) {
base = 8;
} else if (flags == std::ios_base::dec) {
base = 10;
} else if (flags == std::ios_base::hex) {
base = 16;
}
bool foundDigit = false;
bool foundNonZero = false;
if (is.peek() == '0') {
foundDigit = true;
is.ignore();
if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) {
base = 16;
foundDigit = false;
is.ignore();
} else if (base == 0) {
base = 8;
}
}
// Determine the range of digits allowed for this number.
const char* digits = "0123456789abcdefABCDEF";
int maxDigitIndex = 10;
if (base == 8) {
maxDigitIndex = 8;
} else if (base == 16) {
maxDigitIndex = 10 + 6 + 6;
}
// Scan until an invalid digit is found.
for (; is.peek() != EOF; is.ignore()) {
if (memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0) {
if ((foundNonZero || *out != '0') && out < end) {
++out;
foundNonZero = true;
}
foundDigit = true;
} else {
break;
}
}
// Correct the buffer contents for degenerate cases.
if (foundDigit && !foundNonZero) {
*out++ = '0';
} else if (!foundDigit) {
out = buffer;
}
// Terminate the string in the buffer.
*out = '\0';
return base;
}
// Read an integer value from an input stream.
template <class T>
std::istream& IOStreamScanTemplate(std::istream& is, T& value, char type)
{
int state = std::ios_base::goodbit;
// Skip leading whitespace.
std::istream::sentry okay(is);
if (okay) {
try {
// Copy the string to a buffer and construct the format string.
char buffer[KWSYS_IOS_INT64_MAX_DIG];
# if defined(_MSC_VER)
char format[] = "%I64_";
const int typeIndex = 4;
# else
char format[] = "%ll_";
const int typeIndex = 3;
# endif
switch (IOStreamScanStream(is, buffer)) {
case 8:
format[typeIndex] = 'o';
break;
case 0: // Default to decimal if not told otherwise.
case 10:
format[typeIndex] = type;
break;
case 16:
format[typeIndex] = 'x';
break;
};
// Use sscanf to parse the number from the buffer.
T result;
int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0;
// Set flags for resulting state.
if (is.peek() == EOF) {
state |= std::ios_base::eofbit;
}
if (!success) {
state |= std::ios_base::failbit;
} else {
value = result;
}
} catch (...) {
state |= std::ios_base::badbit;
}
}
is.setstate(std::ios_base::iostate(state));
return is;
}
// Print an integer value to an output stream.
template <class T>
std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type)
{
std::ostream::sentry okay(os);
if (okay) {
try {
// Construct the format string.
char format[8];
char* f = format;
*f++ = '%';
if (os.flags() & std::ios_base::showpos) {
*f++ = '+';
}
if (os.flags() & std::ios_base::showbase) {
*f++ = '#';
}
# if defined(_MSC_VER)
*f++ = 'I';
*f++ = '6';
*f++ = '4';
# else
*f++ = 'l';
*f++ = 'l';
# endif
long bflags = os.flags() & std::ios_base::basefield;
if (bflags == std::ios_base::oct) {
*f++ = 'o';
} else if (bflags != std::ios_base::hex) {
*f++ = type;
} else if (os.flags() & std::ios_base::uppercase) {
*f++ = 'X';
} else {
*f++ = 'x';
}
*f = '\0';
// Use sprintf to print to a buffer and then write the
// buffer to the stream.
char buffer[2 * KWSYS_IOS_INT64_MAX_DIG];
sprintf(buffer, format, value);
os << buffer;
} catch (...) {
os.clear(os.rdstate() | std::ios_base::badbit);
}
}
return os;
}
# if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG
// Implement input stream operator for IOStreamSLL.
std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value)
{
return IOStreamScanTemplate(is, value, 'd');
}
// Implement input stream operator for IOStreamULL.
std::istream& IOStreamScan(std::istream& is, IOStreamULL& value)
{
return IOStreamScanTemplate(is, value, 'u');
}
# endif
# if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG
// Implement output stream operator for IOStreamSLL.
std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value)
{
return IOStreamPrintTemplate(os, value, 'd');
}
// Implement output stream operator for IOStreamULL.
std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value)
{
return IOStreamPrintTemplate(os, value, 'u');
}
# endif
} // namespace KWSYS_NAMESPACE
#else
namespace KWSYS_NAMESPACE {
// Create one public symbol in this object file to avoid warnings from
// archivers.
void IOStreamSymbolToAvoidWarning();
void IOStreamSymbolToAvoidWarning()
{
}
} // namespace KWSYS_NAMESPACE
#endif // KWSYS_IOS_NEED_OPERATORS_LL
-126
View File
@@ -1,126 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_IOStream_hxx
#define @KWSYS_NAMESPACE@_IOStream_hxx
#include <iosfwd>
/* Define these macros temporarily to keep the code readable. */
#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
/* Whether istream supports long long. */
#define @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG \
@KWSYS_IOS_HAS_ISTREAM_LONG_LONG@
/* Whether ostream supports long long. */
#define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG \
@KWSYS_IOS_HAS_OSTREAM_LONG_LONG@
/* Determine whether we need to define the streaming operators for
long long or __int64. */
#if @KWSYS_USE_LONG_LONG@
# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG || \
!@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1
namespace @KWSYS_NAMESPACE@ {
typedef long long IOStreamSLL;
typedef unsigned long long IOStreamULL;
}
# endif
#elif defined(_MSC_VER) && _MSC_VER < 1300
# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1
namespace @KWSYS_NAMESPACE@ {
typedef __int64 IOStreamSLL;
typedef unsigned __int64 IOStreamULL;
}
#endif
#if !defined(@KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL)
# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 0
#endif
#if @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL
# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG
/* Input stream operator implementation functions. */
namespace @KWSYS_NAMESPACE@ {
kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamSLL&);
kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamULL&);
}
/* Provide input stream operator for long long. */
# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_LONG_LONG) && \
!defined(KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED)
# define KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED
# define @KWSYS_NAMESPACE@_IOS_ISTREAM_LONG_LONG_DEFINED
inline std::istream& operator>>(std::istream& is,
@KWSYS_NAMESPACE@::IOStreamSLL& value)
{
return @KWSYS_NAMESPACE@::IOStreamScan(is, value);
}
# endif
/* Provide input stream operator for unsigned long long. */
# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_UNSIGNED_LONG_LONG) && \
!defined(KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED)
# define KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED
# define @KWSYS_NAMESPACE@_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED
inline std::istream& operator>>(std::istream& is,
@KWSYS_NAMESPACE@::IOStreamULL& value)
{
return @KWSYS_NAMESPACE@::IOStreamScan(is, value);
}
# endif
# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG */
# if !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
/* Output stream operator implementation functions. */
namespace @KWSYS_NAMESPACE@ {
kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamSLL);
kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamULL);
}
/* Provide output stream operator for long long. */
# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_LONG_LONG) && \
!defined(KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED)
# define KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED
# define @KWSYS_NAMESPACE@_IOS_OSTREAM_LONG_LONG_DEFINED
inline std::ostream& operator<<(std::ostream& os,
@KWSYS_NAMESPACE@::IOStreamSLL value)
{
return @KWSYS_NAMESPACE@::IOStreamPrint(os, value);
}
# endif
/* Provide output stream operator for unsigned long long. */
# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_UNSIGNED_LONG_LONG) && \
!defined(KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED)
# define KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED
# define @KWSYS_NAMESPACE@_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED
inline std::ostream& operator<<(std::ostream& os,
@KWSYS_NAMESPACE@::IOStreamULL value)
{
return @KWSYS_NAMESPACE@::IOStreamPrint(os, value);
}
# endif
# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG */
#endif /* @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL */
/* Undefine temporary macros. */
#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# undef kwsysEXPORT
#endif
/* If building a C++ file in kwsys itself, give the source file
access to the macros without a configured namespace. */
#if defined(KWSYS_NAMESPACE)
# define KWSYS_IOS_HAS_ISTREAM_LONG_LONG \
@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG
# define KWSYS_IOS_HAS_OSTREAM_LONG_LONG \
@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
# define KWSYS_IOS_NEED_OPERATORS_LL @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL
#endif
#endif
-494
View File
@@ -1,494 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(MD5.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
#if 0
# include "MD5.h.in"
#endif
#include <stddef.h> /* size_t */
#include <stdlib.h> /* malloc, free */
#include <string.h> /* memcpy, strlen */
/* This MD5 implementation has been taken from a third party. Slight
modifications to the arrangement of the code have been made to put
it in a single source file instead of a separate header and
implementation file. */
#if defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wcast-align"
#endif
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s
{
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
# define BYTE_ORDER 0
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/)
{
md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
const md5_word_t* X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const md5_byte_t*)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t*)0) & 3)) {
/* data are properly aligned */
X = (const md5_word_t*)data;
} else {
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t* xp = data;
int i;
# if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] =
(md5_word_t)(xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24));
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti) \
t = a + F(b, c, d) + X[k] + (Ti); \
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti) \
t = a + G(b, c, d) + X[k] + (Ti); \
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti) \
t = a + H(b, c, d) + X[k] + (Ti); \
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti) \
t = a + I(b, c, d) + X[k] + (Ti); \
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
/* Initialize the algorithm. */
static void md5_init(md5_state_t* pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
/* Append a string to the message. */
static void md5_append(md5_state_t* pms, const md5_byte_t* data, size_t nbytes)
{
const md5_byte_t* p = data;
size_t left = nbytes;
size_t offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += (md5_word_t)(nbytes >> 29);
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
/* Finish the message and return the digest. */
static void md5_finish(md5_state_t* pms, md5_byte_t digest[16])
{
static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}
#if defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma clang diagnostic pop
#endif
/* Wrap up the MD5 state in our opaque structure. */
struct kwsysMD5_s
{
md5_state_t md5_state;
};
kwsysMD5* kwsysMD5_New(void)
{
/* Allocate a process control structure. */
kwsysMD5* md5 = (kwsysMD5*)malloc(sizeof(kwsysMD5));
if (!md5) {
return 0;
}
return md5;
}
void kwsysMD5_Delete(kwsysMD5* md5)
{
/* Make sure we have an instance. */
if (!md5) {
return;
}
/* Free memory. */
free(md5);
}
void kwsysMD5_Initialize(kwsysMD5* md5)
{
md5_init(&md5->md5_state);
}
void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, int length)
{
size_t dlen;
if (length < 0) {
dlen = strlen((char const*)data);
} else {
dlen = (size_t)length;
}
md5_append(&md5->md5_state, (md5_byte_t const*)data, dlen);
}
void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16])
{
md5_finish(&md5->md5_state, (md5_byte_t*)digest);
}
void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32])
{
unsigned char digest[16];
kwsysMD5_Finalize(md5, digest);
kwsysMD5_DigestToHex(digest, buffer);
}
void kwsysMD5_DigestToHex(unsigned char const digest[16], char buffer[32])
{
/* Map from 4-bit index to hexadecimal representation. */
static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
/* Map each 4-bit block separately. */
char* out = buffer;
int i;
for (i = 0; i < 16; ++i) {
*out++ = hex[digest[i] >> 4];
*out++ = hex[digest[i] & 0xF];
}
}
-97
View File
@@ -1,97 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_MD5_h
#define @KWSYS_NAMESPACE@_MD5_h
#include <@KWSYS_NAMESPACE@/Configure.h>
/* Redefine all public interface symbol names to be in the proper
namespace. These macros are used internally to kwsys only, and are
not visible to user code. Use kwsysHeaderDump.pl to reproduce
these macros after making changes to the interface. */
#if !defined(KWSYS_NAMESPACE)
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsysMD5 kwsys_ns(MD5)
# define kwsysMD5_s kwsys_ns(MD5_s)
# define kwsysMD5_New kwsys_ns(MD5_New)
# define kwsysMD5_Delete kwsys_ns(MD5_Delete)
# define kwsysMD5_Initialize kwsys_ns(MD5_Initialize)
# define kwsysMD5_Append kwsys_ns(MD5_Append)
# define kwsysMD5_Finalize kwsys_ns(MD5_Finalize)
# define kwsysMD5_FinalizeHex kwsys_ns(MD5_FinalizeHex)
# define kwsysMD5_DigestToHex kwsys_ns(MD5_DigestToHex)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/**
* MD5 state data structure.
*/
typedef struct kwsysMD5_s kwsysMD5;
/**
* Create a new MD5 instance. The returned instance is not initialized.
*/
kwsysEXPORT kwsysMD5* kwsysMD5_New(void);
/**
* Delete an old MD5 instance.
*/
kwsysEXPORT void kwsysMD5_Delete(kwsysMD5* md5);
/**
* Initialize a new MD5 digest.
*/
kwsysEXPORT void kwsysMD5_Initialize(kwsysMD5* md5);
/**
* Append data to an MD5 digest. If the given length is negative,
* data will be read up to but not including a terminating null.
*/
kwsysEXPORT void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data,
int length);
/**
* Finalize a MD5 digest and get the 16-byte hash value.
*/
kwsysEXPORT void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]);
/**
* Finalize a MD5 digest and get the 32-bit hexadecimal representation.
*/
kwsysEXPORT void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]);
/**
* Convert a MD5 digest 16-byte value to a 32-byte hexadecimal representation.
*/
kwsysEXPORT void kwsysMD5_DigestToHex(unsigned char const digest[16],
char buffer[32]);
#if defined(__cplusplus)
} /* extern "C" */
#endif
/* If we are building a kwsys .c or .cxx file, let it use these macros.
Otherwise, undefine them to keep the namespace clean. */
#if !defined(KWSYS_NAMESPACE)
# undef kwsys_ns
# undef kwsysEXPORT
# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# undef kwsysMD5
# undef kwsysMD5_s
# undef kwsysMD5_New
# undef kwsysMD5_Delete
# undef kwsysMD5_Initialize
# undef kwsysMD5_Append
# undef kwsysMD5_Finalize
# undef kwsysMD5_FinalizeHex
# undef kwsysMD5_DigestToHex
# endif
#endif
#endif
-544
View File
@@ -1,544 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Process_h
#define @KWSYS_NAMESPACE@_Process_h
#include <@KWSYS_NAMESPACE@/Configure.h>
/* Redefine all public interface symbol names to be in the proper
namespace. These macros are used internally to kwsys only, and are
not visible to user code. Use kwsysHeaderDump.pl to reproduce
these macros after making changes to the interface. */
#if !defined(KWSYS_NAMESPACE)
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsysProcess kwsys_ns(Process)
# define kwsysProcess_s kwsys_ns(Process_s)
# define kwsysProcess_New kwsys_ns(Process_New)
# define kwsysProcess_Delete kwsys_ns(Process_Delete)
# define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand)
# define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand)
# define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout)
# define kwsysProcess_SetWorkingDirectory \
kwsys_ns(Process_SetWorkingDirectory)
# define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile)
# define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative)
# define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared)
# define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach)
# define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow)
# define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput)
# define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim)
# define kwsysProcess_Option_CreateProcessGroup \
kwsys_ns(Process_Option_CreateProcessGroup)
# define kwsysProcess_GetOption kwsys_ns(Process_GetOption)
# define kwsysProcess_SetOption kwsys_ns(Process_SetOption)
# define kwsysProcess_Option_e kwsys_ns(Process_Option_e)
# define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting)
# define kwsysProcess_State_Error kwsys_ns(Process_State_Error)
# define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception)
# define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing)
# define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited)
# define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired)
# define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed)
# define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned)
# define kwsysProcess_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_Exception_e kwsys_ns(Process_Exception_e)
# define kwsysProcess_GetState kwsys_ns(Process_GetState)
# define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException)
# 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_GetStateByIndex kwsys_ns(Process_GetStateByIndex)
# define kwsysProcess_GetExitExceptionByIndex \
kwsys_ns(Process_GetExitExceptionByIndex)
# define kwsysProcess_GetExitCodeByIndex kwsys_ns(Process_GetExitCodeByIndex)
# define kwsysProcess_GetExitValueByIndex \
kwsys_ns(Process_GetExitValueByIndex)
# define kwsysProcess_GetExceptionStringByIndex \
kwsys_ns(Process_GetExceptionStringByIndex)
# define kwsysProcess_GetExitCodeByIndex kwsys_ns(Process_GetExitCodeByIndex)
# define kwsysProcess_Execute kwsys_ns(Process_Execute)
# define kwsysProcess_Disown kwsys_ns(Process_Disown)
# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData)
# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e)
# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None)
# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN)
# define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT)
# define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR)
# define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout)
# define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle)
# define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit)
# define kwsysProcess_Interrupt kwsys_ns(Process_Interrupt)
# define kwsysProcess_Kill kwsys_ns(Process_Kill)
# define kwsysProcess_KillPID kwsys_ns(Process_KillPID)
# define kwsysProcess_ResetStartTime kwsys_ns(Process_ResetStartTime)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/**
* Process control data structure.
*/
typedef struct kwsysProcess_s kwsysProcess;
/* Platform-specific pipe handle type. */
#if defined(_WIN32) && !defined(__CYGWIN__)
typedef void* kwsysProcess_Pipe_Handle;
#else
typedef int kwsysProcess_Pipe_Handle;
#endif
/**
* Create a new Process instance.
*/
kwsysEXPORT kwsysProcess* kwsysProcess_New(void);
/**
* Delete an existing Process instance. If the instance is currently
* executing a process, this blocks until the process terminates.
*/
kwsysEXPORT void kwsysProcess_Delete(kwsysProcess* cp);
/**
* Set the command line to be executed. Argument is an array of
* pointers to the command and each argument. The array must end with
* a NULL pointer. Any previous command lines are removed. Returns
* 1 for success and 0 otherwise.
*/
kwsysEXPORT int kwsysProcess_SetCommand(kwsysProcess* cp,
char const* const* command);
/**
* Add a command line to be executed. Argument is an array of
* pointers to the command and each argument. The array must end with
* a NULL pointer. If this is not the first command added, its
* standard input will be connected to the standard output of the
* previous command. Returns 1 for success and 0 otherwise.
*/
kwsysEXPORT int kwsysProcess_AddCommand(kwsysProcess* cp,
char const* const* command);
/**
* Set the timeout in seconds for the child process. The timeout
* period begins when the child is executed. If the child has not
* terminated when the timeout expires, it will be killed. A
* non-positive (<= 0) value will disable the timeout.
*/
kwsysEXPORT void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout);
/**
* Set the working directory for the child process. The working
* directory can be absolute or relative to the current directory.
* Returns 1 for success and 0 for failure.
*/
kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp,
const char* dir);
/**
* Set the name of a file to be attached to the given pipe. Returns 1
* for success and 0 for failure.
*/
kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe,
const char* file);
/**
* Set whether the given pipe in the child is shared with the parent
* process. The default is no for Pipe_STDOUT and Pipe_STDERR and yes
* for Pipe_STDIN.
*/
kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe,
int shared);
/**
* Specify a platform-specific native pipe for use as one of the child
* interface pipes. The native pipe is specified by an array of two
* descriptors or handles. The first entry in the array (index 0)
* should be the read end of the pipe. The second entry in the array
* (index 1) should be the write end of the pipe. If a null pointer
* is given the option will be disabled.
*
* For Pipe_STDIN the native pipe is connected to the first child in
* the pipeline as its stdin. After the children are created the
* write end of the pipe will be closed in the child process and the
* read end will be closed in the parent process.
*
* For Pipe_STDOUT and Pipe_STDERR the pipe is connected to the last
* child as its stdout or stderr. After the children are created the
* write end of the pipe will be closed in the parent process and the
* read end will be closed in the child process.
*/
kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe,
kwsysProcess_Pipe_Handle p[2]);
/**
* Get/Set a possibly platform-specific option. Possible options are:
*
* kwsysProcess_Option_Detach = Whether to detach the process.
* 0 = No (default)
* 1 = Yes
*
* kwsysProcess_Option_HideWindow = Whether to hide window on Windows.
* 0 = No (default)
* 1 = Yes
*
* kwsysProcess_Option_MergeOutput = Whether to merge stdout/stderr.
* No content will be returned as stderr.
* Any actual stderr will be on stdout.
* 0 = No (default)
* 1 = Yes
*
* kwsysProcess_Option_Verbatim = Whether SetCommand and AddCommand
* should treat the first argument
* as a verbatim command line
* and ignore the rest of the arguments.
* 0 = No (default)
* 1 = Yes
*
* kwsysProcess_Option_CreateProcessGroup = Whether to place the process in a
* new process group. This is
* useful if you want to send Ctrl+C
* to the process. On UNIX, also
* places the process in a new
* session.
* 0 = No (default)
* 1 = Yes
*/
kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId);
kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
int value);
enum kwsysProcess_Option_e
{
kwsysProcess_Option_HideWindow,
kwsysProcess_Option_Detach,
kwsysProcess_Option_MergeOutput,
kwsysProcess_Option_Verbatim,
kwsysProcess_Option_CreateProcessGroup
};
/**
* Get the current state of the Process instance. Possible states are:
*
* kwsysProcess_State_Starting = Execute has not yet been called.
* kwsysProcess_State_Error = Error administrating the child process.
* kwsysProcess_State_Exception = Child process exited abnormally.
* kwsysProcess_State_Executing = Child process is currently running.
* kwsysProcess_State_Exited = Child process exited normally.
* kwsysProcess_State_Expired = Child process's timeout expired.
* kwsysProcess_State_Killed = Child process terminated by Kill method.
* kwsysProcess_State_Disowned = Child is no longer managed by this object.
*/
kwsysEXPORT int kwsysProcess_GetState(kwsysProcess* cp);
enum kwsysProcess_State_e
{
kwsysProcess_State_Starting,
kwsysProcess_State_Error,
kwsysProcess_State_Exception,
kwsysProcess_State_Executing,
kwsysProcess_State_Exited,
kwsysProcess_State_Expired,
kwsysProcess_State_Killed,
kwsysProcess_State_Disowned
};
/**
* When GetState returns "Exception", this method returns a
* platform-independent description of the exceptional behavior that
* caused the child to terminate abnormally. Possible exceptions are:
*
* kwsysProcess_Exception_None = No exceptional behavior occurred.
* kwsysProcess_Exception_Fault = Child crashed with a memory fault.
* kwsysProcess_Exception_Illegal = Child crashed with an illegal
* instruction.
* kwsysProcess_Exception_Interrupt = Child was interrupted by user
* (Cntl-C/Break).
* kwsysProcess_Exception_Numerical = Child crashed with a numerical
* exception.
* kwsysProcess_Exception_Other = Child terminated for another reason.
*/
kwsysEXPORT int kwsysProcess_GetExitException(kwsysProcess* cp);
enum kwsysProcess_Exception_e
{
kwsysProcess_Exception_None,
kwsysProcess_Exception_Fault,
kwsysProcess_Exception_Illegal,
kwsysProcess_Exception_Interrupt,
kwsysProcess_Exception_Numerical,
kwsysProcess_Exception_Other
};
/**
* When GetState returns "Exited" or "Exception", this method returns
* the platform-specific raw exit code of the process. UNIX platforms
* should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access
* this value. Windows users should compare the value to the various
* EXCEPTION_* values.
*
* If GetState returns "Exited", use GetExitValue to get the
* platform-independent child return value.
*/
kwsysEXPORT int kwsysProcess_GetExitCode(kwsysProcess* cp);
/**
* When GetState returns "Exited", this method returns the child's
* platform-independent exit code (such as the value returned by the
* child's main).
*/
kwsysEXPORT int kwsysProcess_GetExitValue(kwsysProcess* cp);
/**
* When GetState returns "Error", this method returns a string
* describing the problem. Otherwise, it returns NULL.
*/
kwsysEXPORT const char* kwsysProcess_GetErrorString(kwsysProcess* cp);
/**
* When GetState returns "Exception", this method returns a string
* describing the problem. Otherwise, it returns NULL.
*/
kwsysEXPORT const char* kwsysProcess_GetExceptionString(kwsysProcess* cp);
/**
* Get the current state of the Process instance. Possible states are:
*
* kwsysProcess_StateByIndex_Starting = Execute has not yet been called.
* kwsysProcess_StateByIndex_Exception = Child process exited abnormally.
* kwsysProcess_StateByIndex_Exited = Child process exited normally.
* kwsysProcess_StateByIndex_Error = Error getting the child return code.
*/
kwsysEXPORT int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx);
enum kwsysProcess_StateByIndex_e
{
kwsysProcess_StateByIndex_Starting = kwsysProcess_State_Starting,
kwsysProcess_StateByIndex_Exception = kwsysProcess_State_Exception,
kwsysProcess_StateByIndex_Exited = kwsysProcess_State_Exited,
kwsysProcess_StateByIndex_Error = kwsysProcess_State_Error
};
/**
* 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_GetExitExceptionByIndex(kwsysProcess* cp,
int idx);
/**
* 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_GetExitCodeByIndex(kwsysProcess* cp, int idx);
/**
* 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_GetExitValueByIndex(kwsysProcess* cp, int idx);
/**
* When GetState returns "Exception", this method returns a string
* describing the problem. Otherwise, it returns NULL.
*/
kwsysEXPORT const char* kwsysProcess_GetExceptionStringByIndex(
kwsysProcess* cp, int idx);
/**
* 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 immediately. The
* argument is:
*
* timeout = Specifies the maximum time this call may block. Upon
* returning due to child termination, the elapsed time
* is subtracted from the given value. A NULL pointer
* passed for this argument indicates no timeout for the
* call.
*
* Return value will be one of:
*
* 0 = Child did not terminate within timeout specified for
* the call. Time elapsed has been subtracted from timeout
* argument.
* 1 = Child has terminated or was not running.
*/
kwsysEXPORT int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout);
/**
* Interrupt the process group for the child process that is currently
* running by sending it the appropriate operating-system specific signal.
* The caller should call WaitForExit after this returns to wait for the
* child to terminate.
*
* WARNING: If you didn't specify kwsysProcess_Option_CreateProcessGroup,
* you will interrupt your own process group.
*/
kwsysEXPORT void kwsysProcess_Interrupt(kwsysProcess* cp);
/**
* Forcefully terminate the child process that is currently running.
* The caller should call WaitForExit after this returns to wait for
* the child to terminate.
*/
kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
/**
* Same as kwsysProcess_Kill using process ID to locate process to
* terminate.
* @see kwsysProcess_Kill(kwsysProcess* cp)
*/
kwsysEXPORT void kwsysProcess_KillPID(unsigned long);
/**
* Reset the start time of the child process to the current time.
*/
kwsysEXPORT void kwsysProcess_ResetStartTime(kwsysProcess* cp);
#if defined(__cplusplus)
} /* extern "C" */
#endif
/* If we are building a kwsys .c or .cxx file, let it use these macros.
Otherwise, undefine them to keep the namespace clean. */
#if !defined(KWSYS_NAMESPACE)
# undef kwsys_ns
# undef kwsysEXPORT
# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# undef kwsysProcess
# undef kwsysProcess_s
# undef kwsysProcess_New
# undef kwsysProcess_Delete
# undef kwsysProcess_SetCommand
# undef kwsysProcess_AddCommand
# undef kwsysProcess_SetTimeout
# undef kwsysProcess_SetWorkingDirectory
# undef kwsysProcess_SetPipeFile
# undef kwsysProcess_SetPipeNative
# undef kwsysProcess_SetPipeShared
# undef kwsysProcess_Option_Detach
# undef kwsysProcess_Option_HideWindow
# undef kwsysProcess_Option_MergeOutput
# undef kwsysProcess_Option_Verbatim
# undef kwsysProcess_Option_CreateProcessGroup
# undef kwsysProcess_GetOption
# undef kwsysProcess_SetOption
# undef kwsysProcess_Option_e
# undef kwsysProcess_State_Starting
# undef kwsysProcess_State_Error
# undef kwsysProcess_State_Exception
# undef kwsysProcess_State_Executing
# undef kwsysProcess_State_Exited
# undef kwsysProcess_State_Expired
# undef kwsysProcess_State_Killed
# undef kwsysProcess_State_Disowned
# undef kwsysProcess_GetState
# undef kwsysProcess_State_e
# undef kwsysProcess_Exception_None
# undef kwsysProcess_Exception_Fault
# undef kwsysProcess_Exception_Illegal
# undef kwsysProcess_Exception_Interrupt
# undef kwsysProcess_Exception_Numerical
# undef kwsysProcess_Exception_Other
# undef kwsysProcess_GetExitException
# undef kwsysProcess_Exception_e
# undef kwsysProcess_GetExitCode
# undef kwsysProcess_GetExitValue
# undef kwsysProcess_GetErrorString
# undef kwsysProcess_GetExceptionString
# undef kwsysProcess_Execute
# undef kwsysProcess_Disown
# undef kwsysProcess_WaitForData
# undef kwsysProcess_Pipes_e
# undef kwsysProcess_Pipe_None
# undef kwsysProcess_Pipe_STDIN
# undef kwsysProcess_Pipe_STDOUT
# undef kwsysProcess_Pipe_STDERR
# undef kwsysProcess_Pipe_Timeout
# undef kwsysProcess_Pipe_Handle
# undef kwsysProcess_WaitForExit
# undef kwsysProcess_Interrupt
# undef kwsysProcess_Kill
# undef kwsysProcess_ResetStartTime
# endif
#endif
#endif
-2920
View File
@@ -1,2920 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Process.h)
#include KWSYS_HEADER(System.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
#if 0
# include "Process.h.in"
# include "System.h.in"
#endif
/*
Implementation for UNIX
On UNIX, a child process is forked to exec the program. Three output
pipes are read by the parent process using a select call to block
until data are ready. Two of the pipes are stdout and stderr for the
child. The third is a special pipe populated by a signal handler to
indicate that a child has terminated. This is used in conjunction
with the timeout on the select call to implement a timeout for program
even when it closes stdout and stderr and at the same time avoiding
races.
*/
/*
TODO:
We cannot create the pipeline of processes in suspended states. How
do we cleanup processes already started when one fails to load? Right
now we are just killing them, which is probably not the right thing to
do.
*/
#if defined(__CYGWIN__)
/* Increase the file descriptor limit for select() before including
related system headers. (Default: 64) */
# define FD_SETSIZE 16384
#endif
#include <assert.h> /* assert */
#include <ctype.h> /* isspace */
#include <dirent.h> /* DIR, dirent */
#include <errno.h> /* errno */
#include <fcntl.h> /* fcntl */
#include <signal.h> /* sigaction */
#include <stddef.h> /* ptrdiff_t */
#include <stdio.h> /* snprintf */
#include <stdlib.h> /* malloc, free */
#include <string.h> /* strdup, strerror, memset */
#include <sys/stat.h> /* open mode */
#include <sys/time.h> /* struct timeval */
#include <sys/types.h> /* pid_t, fd_set */
#include <sys/wait.h> /* waitpid */
#include <time.h> /* gettimeofday */
#include <unistd.h> /* pipe, close, fork, execvp, select, _exit */
#if defined(__VMS)
# define KWSYSPE_VMS_NONBLOCK , O_NONBLOCK
#else
# define KWSYSPE_VMS_NONBLOCK
#endif
#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T
typedef ptrdiff_t kwsysProcess_ptrdiff_t;
#else
typedef int kwsysProcess_ptrdiff_t;
#endif
#if defined(KWSYS_C_HAS_SSIZE_T) && KWSYS_C_HAS_SSIZE_T
typedef ssize_t kwsysProcess_ssize_t;
#else
typedef int kwsysProcess_ssize_t;
#endif
#if defined(__BEOS__) && !defined(__ZETA__)
/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
# include <be/kernel/OS.h>
static inline void kwsysProcess_usleep(unsigned int msec)
{
snooze(msec);
}
#else
# define kwsysProcess_usleep usleep
#endif
/*
* BeOS's select() works like WinSock: it's for networking only, and
* doesn't work with Unix file handles...socket and file handles are
* different namespaces (the same descriptor means different things in
* each context!)
*
* So on Unix-like systems where select() is flakey, we'll set the
* pipes' file handles to be non-blocking and just poll them directly
* without select().
*/
#if !defined(__BEOS__) && !defined(__VMS) && !defined(__MINT__) && \
!defined(KWSYSPE_USE_SELECT)
# define KWSYSPE_USE_SELECT 1
#endif
/* Some platforms do not have siginfo on their signal handlers. */
#if defined(SA_SIGINFO) && !defined(__BEOS__)
# define KWSYSPE_USE_SIGINFO 1
#endif
/* The number of pipes for the child's output. The standard stdout
and stderr pipes are the first two. One more pipe is used to
detect when the child process has terminated. The third pipe is
not given to the child process, so it cannot close it until it
terminates. */
#define KWSYSPE_PIPE_COUNT 3
#define KWSYSPE_PIPE_STDOUT 0
#define KWSYSPE_PIPE_STDERR 1
#define KWSYSPE_PIPE_SIGNAL 2
/* The maximum amount to read from a pipe at a time. */
#define KWSYSPE_PIPE_BUFFER_SIZE 1024
/* Keep track of times using a signed representation. Switch to the
native (possibly unsigned) representation only when calling native
functions. */
typedef struct timeval kwsysProcessTimeNative;
typedef struct kwsysProcessTime_s kwsysProcessTime;
struct kwsysProcessTime_s
{
long tv_sec;
long tv_usec;
};
typedef struct kwsysProcessCreateInformation_s
{
int StdIn;
int StdOut;
int StdErr;
int ErrorPipe[2];
} kwsysProcessCreateInformation;
static void kwsysProcessVolatileFree(volatile void* p);
static int kwsysProcessInitialize(kwsysProcess* cp);
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
static void kwsysProcessCleanupDescriptor(int* pfd);
static void kwsysProcessClosePipes(kwsysProcess* cp);
static int kwsysProcessSetNonBlocking(int fd);
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
kwsysProcessCreateInformation* si);
static void kwsysProcessDestroy(kwsysProcess* cp);
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name);
static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]);
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime);
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
double* userTimeout,
kwsysProcessTimeNative* timeoutLength,
int zeroIsExpired);
static kwsysProcessTime kwsysProcessTimeGetCurrent(void);
static double kwsysProcessTimeToDouble(kwsysProcessTime t);
static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
kwsysProcessTime in2);
static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
kwsysProcessTime in2);
static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig,
int idx);
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
/* A structure containing results data for each process. */
typedef struct kwsysProcessResults_s kwsysProcessResults;
struct kwsysProcessResults_s
{
/* The status of the child process. */
int State;
/* The exceptional behavior that terminated the process, if any. */
int ExitException;
/* The process exit code. */
int ExitCode;
/* The process return code, if any. */
int ExitValue;
/* Description for the ExitException. */
char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1];
};
/* Structure containing data used to implement the child's execution. */
struct kwsysProcess_s
{
/* The command lines to execute. */
char*** Commands;
volatile int NumberOfCommands;
/* Descriptors for the read ends of the child's output pipes and
the signal pipe. */
int PipeReadEnds[KWSYSPE_PIPE_COUNT];
/* Descriptors for the child's ends of the pipes.
Used temporarily during process creation. */
int PipeChildStd[3];
/* Write descriptor for child termination signal pipe. */
int SignalPipe;
/* Buffer for pipe data. */
char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
/* Process IDs returned by the calls to fork. Everything is volatile
because the signal handler accesses them. You must be very careful
when reaping PIDs or modifying this array to avoid race conditions. */
volatile pid_t* volatile ForkPIDs;
/* Flag for whether the children were terminated by a failed select. */
int SelectError;
/* The timeout length. */
double Timeout;
/* The working directory for the process. */
char* WorkingDirectory;
/* Whether to create the child as a detached process. */
int OptionDetach;
/* Whether the child was created as a detached process. */
int Detached;
/* Whether to treat command lines as verbatim. */
int Verbatim;
/* Whether to merge stdout/stderr of the child. */
int MergeOutput;
/* Whether to create the process in a new process group. */
volatile sig_atomic_t CreateProcessGroup;
/* Time at which the child started. Negative for no timeout. */
kwsysProcessTime StartTime;
/* Time at which the child will timeout. Negative for no timeout. */
kwsysProcessTime TimeoutTime;
/* Flag for whether the timeout expired. */
int TimeoutExpired;
/* The number of pipes left open during execution. */
int PipesLeft;
#if KWSYSPE_USE_SELECT
/* File descriptor set for call to select. */
fd_set PipeSet;
#endif
/* The number of children still executing. */
int CommandsLeft;
/* The status of the process structure. Must be atomic because
the signal handler checks this to avoid a race. */
volatile sig_atomic_t State;
/* Whether the process was killed. */
volatile sig_atomic_t Killed;
/* Buffer for error message in case of failure. */
char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1];
/* process results. */
kwsysProcessResults* ProcessResults;
/* 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);
free(cp->CommandExitCodes);
free(cp->ProcessResults);
free(cp);
}
int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
{
int i;
if (!cp) {
return 0;
}
for (i = 0; i < cp->NumberOfCommands; ++i) {
char** c = cp->Commands[i];
while (*c) {
free(*c++);
}
free(cp->Commands[i]);
}
cp->NumberOfCommands = 0;
if (cp->Commands) {
free(cp->Commands);
cp->Commands = 0;
}
if (command) {
return kwsysProcess_AddCommand(cp, command);
}
return 1;
}
int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
{
int newNumberOfCommands;
char*** newCommands;
/* Make sure we have a command to add. */
if (!cp || !command || !*command) {
return 0;
}
/* Allocate a new array for command pointers. */
newNumberOfCommands = cp->NumberOfCommands + 1;
if (!(newCommands =
(char***)malloc(sizeof(char**) * (size_t)(newNumberOfCommands)))) {
/* Out of memory. */
return 0;
}
/* Copy any existing commands into the new array. */
{
int i;
for (i = 0; i < cp->NumberOfCommands; ++i) {
newCommands[i] = cp->Commands[i];
}
}
/* Add the new command. */
if (cp->Verbatim) {
/* In order to run the given command line verbatim we need to
parse it. */
newCommands[cp->NumberOfCommands] =
kwsysSystem_Parse_CommandForUnix(*command, 0);
if (!newCommands[cp->NumberOfCommands] ||
!newCommands[cp->NumberOfCommands][0]) {
/* Out of memory or no command parsed. */
free(newCommands);
return 0;
}
} else {
/* Copy each argument string individually. */
char const* const* c = command;
kwsysProcess_ptrdiff_t n = 0;
kwsysProcess_ptrdiff_t i = 0;
while (*c++)
;
n = c - command - 1;
newCommands[cp->NumberOfCommands] =
(char**)malloc((size_t)(n + 1) * sizeof(char*));
if (!newCommands[cp->NumberOfCommands]) {
/* Out of memory. */
free(newCommands);
return 0;
}
for (i = 0; i < n; ++i) {
assert(command[i]); /* Quiet Clang scan-build. */
newCommands[cp->NumberOfCommands][i] = strdup(command[i]);
if (!newCommands[cp->NumberOfCommands][i]) {
break;
}
}
if (i < n) {
/* Out of memory. */
for (; i > 0; --i) {
free(newCommands[cp->NumberOfCommands][i - 1]);
}
free(newCommands);
return 0;
}
newCommands[cp->NumberOfCommands][n] = 0;
}
/* Successfully allocated new command array. Free the old array. */
free(cp->Commands);
cp->Commands = newCommands;
cp->NumberOfCommands = newNumberOfCommands;
return 1;
}
void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
{
if (!cp) {
return;
}
cp->Timeout = timeout;
if (cp->Timeout < 0) {
cp->Timeout = 0;
}
// Force recomputation of TimeoutTime.
cp->TimeoutTime.tv_sec = -1;
}
int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
{
if (!cp) {
return 0;
}
if (cp->WorkingDirectory == dir) {
return 1;
}
if (cp->WorkingDirectory && dir && strcmp(cp->WorkingDirectory, dir) == 0) {
return 1;
}
if (cp->WorkingDirectory) {
free(cp->WorkingDirectory);
cp->WorkingDirectory = 0;
}
if (dir) {
cp->WorkingDirectory = strdup(dir);
if (!cp->WorkingDirectory) {
return 0;
}
}
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 = strdup(file);
if (!*pfile) {
return 0;
}
}
/* If we are redirecting the pipe, do not share it or use a native
pipe. */
if (*pfile) {
kwsysProcess_SetPipeNative(cp, prPipe, 0);
kwsysProcess_SetPipeShared(cp, prPipe, 0);
}
return 1;
}
void kwsysProcess_SetPipeShared(kwsysProcess* cp, int prPipe, int shared)
{
if (!cp) {
return;
}
switch (prPipe) {
case kwsysProcess_Pipe_STDIN:
cp->PipeSharedSTDIN = shared ? 1 : 0;
break;
case kwsysProcess_Pipe_STDOUT:
cp->PipeSharedSTDOUT = shared ? 1 : 0;
break;
case kwsysProcess_Pipe_STDERR:
cp->PipeSharedSTDERR = shared ? 1 : 0;
break;
default:
return;
}
/* If we are sharing the pipe, do not redirect it to a file or use a
native pipe. */
if (shared) {
kwsysProcess_SetPipeFile(cp, prPipe, 0);
kwsysProcess_SetPipeNative(cp, prPipe, 0);
}
}
void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, int p[2])
{
int* pPipeNative = 0;
if (!cp) {
return;
}
switch (prPipe) {
case kwsysProcess_Pipe_STDIN:
pPipeNative = cp->PipeNativeSTDIN;
break;
case kwsysProcess_Pipe_STDOUT:
pPipeNative = cp->PipeNativeSTDOUT;
break;
case kwsysProcess_Pipe_STDERR:
pPipeNative = cp->PipeNativeSTDERR;
break;
default:
return;
}
/* Copy the native pipe descriptors provided. */
if (p) {
pPipeNative[0] = p[0];
pPipeNative[1] = p[1];
} else {
pPipeNative[0] = -1;
pPipeNative[1] = -1;
}
/* If we are using a native pipe, do not share it or redirect it to
a file. */
if (p) {
kwsysProcess_SetPipeFile(cp, prPipe, 0);
kwsysProcess_SetPipeShared(cp, prPipe, 0);
}
}
int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
{
if (!cp) {
return 0;
}
switch (optionId) {
case kwsysProcess_Option_Detach:
return cp->OptionDetach;
case kwsysProcess_Option_MergeOutput:
return cp->MergeOutput;
case kwsysProcess_Option_Verbatim:
return cp->Verbatim;
case kwsysProcess_Option_CreateProcessGroup:
return cp->CreateProcessGroup;
default:
return 0;
}
}
void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
{
if (!cp) {
return;
}
switch (optionId) {
case kwsysProcess_Option_Detach:
cp->OptionDetach = value;
break;
case kwsysProcess_Option_MergeOutput:
cp->MergeOutput = value;
break;
case kwsysProcess_Option_Verbatim:
cp->Verbatim = value;
break;
case kwsysProcess_Option_CreateProcessGroup:
cp->CreateProcessGroup = value;
break;
default:
break;
}
}
int kwsysProcess_GetState(kwsysProcess* cp)
{
return cp ? cp->State : kwsysProcess_State_Error;
}
int kwsysProcess_GetExitException(kwsysProcess* cp)
{
return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException
: kwsysProcess_Exception_Other;
}
int kwsysProcess_GetExitCode(kwsysProcess* cp)
{
return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode
: 0;
}
int kwsysProcess_GetExitValue(kwsysProcess* cp)
{
return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
? cp->ProcessResults[cp->NumberOfCommands - 1].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 && cp->ProcessResults && (cp->NumberOfCommands > 0))) {
return "GetExceptionString called with NULL process management structure";
} else if (cp->State == kwsysProcess_State_Exception) {
return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString;
}
return "No exception";
}
/* the index should be in array bound. */
#define KWSYSPE_IDX_CHK(RET) \
if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \
return RET; \
}
int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK(kwsysProcess_State_Error)
return cp->ProcessResults[idx].State;
}
int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other)
return cp->ProcessResults[idx].ExitException;
}
int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK(-1)
return cp->ProcessResults[idx].ExitValue;
}
int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK(-1)
return cp->CommandExitCodes[idx];
}
const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management "
"structure or index out of bound")
if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) {
return cp->ProcessResults[idx].ExitExceptionString;
}
return "No exception";
}
#undef KWSYSPE_IDX_CHK
void kwsysProcess_Execute(kwsysProcess* cp)
{
int i;
/* Do not execute a second copy simultaneously. */
if (!cp || cp->State == kwsysProcess_State_Executing) {
return;
}
/* Make sure we have something to run. */
if (cp->NumberOfCommands < 1) {
strcpy(cp->ErrorMessage, "No command");
cp->State = kwsysProcess_State_Error;
return;
}
/* Initialize the control structure for a new process. */
if (!kwsysProcessInitialize(cp)) {
strcpy(cp->ErrorMessage, "Out of memory");
cp->State = kwsysProcess_State_Error;
return;
}
#if defined(__VMS)
/* Make sure pipes behave like streams on VMS. */
if (!kwsysProcessSetVMSFeature("DECC$STREAM_PIPE", 1)) {
kwsysProcessCleanup(cp, 1);
return;
}
#endif
/* Save the real working directory of this process and change to
the working directory for the child processes. This is needed
to make pipe file paths evaluate correctly. */
if (cp->WorkingDirectory) {
int r;
if (!getcwd(cp->RealWorkingDirectory,
(size_t)(cp->RealWorkingDirectoryLength))) {
kwsysProcessCleanup(cp, 1);
return;
}
/* Some platforms specify that the chdir call may be
interrupted. Repeat the call until it finishes. */
while (((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR))
;
if (r < 0) {
kwsysProcessCleanup(cp, 1);
return;
}
}
/* If not running a detached child, add this object to the global
set of process objects that wish to be notified when a child
exits. */
if (!cp->OptionDetach) {
if (!kwsysProcessesAdd(cp)) {
kwsysProcessCleanup(cp, 1);
return;
}
}
/* Setup the stdin pipe for the first process. */
if (cp->PipeFileSTDIN) {
/* Open a file for the child's stdin to read. */
cp->PipeChildStd[0] = open(cp->PipeFileSTDIN, O_RDONLY);
if (cp->PipeChildStd[0] < 0) {
kwsysProcessCleanup(cp, 1);
return;
}
/* Set close-on-exec flag on the pipe's end. */
if (fcntl(cp->PipeChildStd[0], F_SETFD, FD_CLOEXEC) < 0) {
kwsysProcessCleanup(cp, 1);
return;
}
} else if (cp->PipeSharedSTDIN) {
cp->PipeChildStd[0] = 0;
} else if (cp->PipeNativeSTDIN[0] >= 0) {
cp->PipeChildStd[0] = cp->PipeNativeSTDIN[0];
/* Set close-on-exec flag on the pipe's ends. The read end will
be dup2-ed into the stdin descriptor after the fork but before
the exec. */
if ((fcntl(cp->PipeNativeSTDIN[0], F_SETFD, FD_CLOEXEC) < 0) ||
(fcntl(cp->PipeNativeSTDIN[1], F_SETFD, FD_CLOEXEC) < 0)) {
kwsysProcessCleanup(cp, 1);
return;
}
} else {
cp->PipeChildStd[0] = -1;
}
/* Create the output pipe for the last process.
We always create this so the pipe can be passed to select even if
it will report closed immediately. */
{
/* Create the pipe. */
int p[2];
if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) {
kwsysProcessCleanup(cp, 1);
return;
}
/* Store the pipe. */
cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = p[0];
cp->PipeChildStd[1] = p[1];
/* Set close-on-exec flag on the pipe's ends. */
if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
(fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) {
kwsysProcessCleanup(cp, 1);
return;
}
/* Set to non-blocking in case select lies, or for the polling
implementation. */
if (!kwsysProcessSetNonBlocking(p[0])) {
kwsysProcessCleanup(cp, 1);
return;
}
}
if (cp->PipeFileSTDOUT) {
/* Use a file for stdout. */
if (!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
cp->PipeFileSTDOUT)) {
kwsysProcessCleanup(cp, 1);
return;
}
} else if (cp->PipeSharedSTDOUT) {
/* Use the parent stdout. */
kwsysProcessCleanupDescriptor(&cp->PipeChildStd[1]);
cp->PipeChildStd[1] = 1;
} else if (cp->PipeNativeSTDOUT[1] >= 0) {
/* Use the given descriptor for stdout. */
if (!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[1],
cp->PipeNativeSTDOUT)) {
kwsysProcessCleanup(cp, 1);
return;
}
}
/* Create stderr pipe to be shared by all processes in the pipeline.
We always create this so the pipe can be passed to select even if
it will report closed immediately. */
{
/* Create the pipe. */
int p[2];
if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) {
kwsysProcessCleanup(cp, 1);
return;
}
/* Store the pipe. */
cp->PipeReadEnds[KWSYSPE_PIPE_STDERR] = p[0];
cp->PipeChildStd[2] = p[1];
/* Set close-on-exec flag on the pipe's ends. */
if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
(fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) {
kwsysProcessCleanup(cp, 1);
return;
}
/* Set to non-blocking in case select lies, or for the polling
implementation. */
if (!kwsysProcessSetNonBlocking(p[0])) {
kwsysProcessCleanup(cp, 1);
return;
}
}
if (cp->PipeFileSTDERR) {
/* Use a file for stderr. */
if (!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
cp->PipeFileSTDERR)) {
kwsysProcessCleanup(cp, 1);
return;
}
} else if (cp->PipeSharedSTDERR) {
/* Use the parent stderr. */
kwsysProcessCleanupDescriptor(&cp->PipeChildStd[2]);
cp->PipeChildStd[2] = 2;
} else if (cp->PipeNativeSTDERR[1] >= 0) {
/* Use the given handle for stderr. */
if (!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[2],
cp->PipeNativeSTDERR)) {
kwsysProcessCleanup(cp, 1);
return;
}
}
/* The timeout period starts now. */
cp->StartTime = kwsysProcessTimeGetCurrent();
cp->TimeoutTime.tv_sec = -1;
cp->TimeoutTime.tv_usec = -1;
/* Create the pipeline of processes. */
{
kwsysProcessCreateInformation si = { -1, -1, -1, { -1, -1 } };
int nextStdIn = cp->PipeChildStd[0];
for (i = 0; i < cp->NumberOfCommands; ++i) {
/* Setup the process's pipes. */
si.StdIn = nextStdIn;
if (i == cp->NumberOfCommands - 1) {
nextStdIn = -1;
si.StdOut = cp->PipeChildStd[1];
} else {
/* Create a pipe to sit between the children. */
int p[2] = { -1, -1 };
if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) {
if (nextStdIn != cp->PipeChildStd[0]) {
kwsysProcessCleanupDescriptor(&nextStdIn);
}
kwsysProcessCleanup(cp, 1);
return;
}
/* Set close-on-exec flag on the pipe's ends. */
if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
(fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) {
close(p[0]);
close(p[1]);
if (nextStdIn != cp->PipeChildStd[0]) {
kwsysProcessCleanupDescriptor(&nextStdIn);
}
kwsysProcessCleanup(cp, 1);
return;
}
nextStdIn = p[0];
si.StdOut = p[1];
}
si.StdErr = cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2];
{
int res = kwsysProcessCreate(cp, i, &si);
/* Close our copies of pipes used between children. */
if (si.StdIn != cp->PipeChildStd[0]) {
kwsysProcessCleanupDescriptor(&si.StdIn);
}
if (si.StdOut != cp->PipeChildStd[1]) {
kwsysProcessCleanupDescriptor(&si.StdOut);
}
if (si.StdErr != cp->PipeChildStd[2] && !cp->MergeOutput) {
kwsysProcessCleanupDescriptor(&si.StdErr);
}
if (!res) {
kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]);
kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]);
if (nextStdIn != cp->PipeChildStd[0]) {
kwsysProcessCleanupDescriptor(&nextStdIn);
}
kwsysProcessCleanup(cp, 1);
return;
}
}
}
}
/* The parent process does not need the child's pipe ends. */
for (i = 0; i < 3; ++i) {
kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]);
}
/* Restore the working directory. */
if (cp->RealWorkingDirectory) {
/* Some platforms specify that the chdir call may be
interrupted. Repeat the call until it finishes. */
while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR))
;
free(cp->RealWorkingDirectory);
cp->RealWorkingDirectory = 0;
}
/* All the pipes are now open. */
cp->PipesLeft = KWSYSPE_PIPE_COUNT;
/* The process has now started. */
cp->State = kwsysProcess_State_Executing;
cp->Detached = cp->OptionDetach;
}
kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp)
{
/* Make sure a detached child process is running. */
if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
cp->TimeoutExpired || cp->Killed) {
return;
}
/* Close all the pipes safely. */
kwsysProcessClosePipes(cp);
/* We will not wait for exit, so cleanup now. */
kwsysProcessCleanup(cp, 0);
/* The process has been disowned. */
cp->State = kwsysProcess_State_Disowned;
}
typedef struct kwsysProcessWaitData_s
{
int Expired;
int PipeId;
int User;
double* UserTimeout;
kwsysProcessTime TimeoutTime;
} kwsysProcessWaitData;
static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
kwsysProcessWaitData* wd);
int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
double* userTimeout)
{
kwsysProcessTime userStartTime = { 0, 0 };
kwsysProcessWaitData wd = { 0, kwsysProcess_Pipe_None, 0, 0, { 0, 0 } };
wd.UserTimeout = userTimeout;
/* Make sure we are executing a process. */
if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
cp->TimeoutExpired) {
return kwsysProcess_Pipe_None;
}
/* Record the time at which user timeout period starts. */
if (userTimeout) {
userStartTime = kwsysProcessTimeGetCurrent();
}
/* Calculate the time at which a timeout will expire, and whether it
is the user or process timeout. */
wd.User = kwsysProcessGetTimeoutTime(cp, userTimeout, &wd.TimeoutTime);
/* Data can only be available when pipes are open. If the process
is not running, cp->PipesLeft will be 0. */
while (cp->PipesLeft > 0 &&
!kwsysProcessWaitForPipe(cp, data, length, &wd)) {
}
/* Update the user timeout. */
if (userTimeout) {
kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
kwsysProcessTime difference =
kwsysProcessTimeSubtract(userEndTime, userStartTime);
double d = kwsysProcessTimeToDouble(difference);
*userTimeout -= d;
if (*userTimeout < 0) {
*userTimeout = 0;
}
}
/* Check what happened. */
if (wd.PipeId) {
/* Data are ready on a pipe. */
return wd.PipeId;
} else if (wd.Expired) {
/* A timeout has expired. */
if (wd.User) {
/* The user timeout has expired. It has no time left. */
return kwsysProcess_Pipe_Timeout;
} else {
/* The process timeout has expired. Kill the children now. */
kwsysProcess_Kill(cp);
cp->Killed = 0;
cp->TimeoutExpired = 1;
return kwsysProcess_Pipe_None;
}
} else {
/* No pipes are left open. */
return kwsysProcess_Pipe_None;
}
}
static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
kwsysProcessWaitData* wd)
{
int i;
kwsysProcessTimeNative timeoutLength;
#if KWSYSPE_USE_SELECT
int numReady = 0;
int max = -1;
kwsysProcessTimeNative* timeout = 0;
/* Check for any open pipes with data reported ready by the last
call to select. According to "man select_tut" we must deal
with all descriptors reported by a call to select before
passing them to another select call. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
if (cp->PipeReadEnds[i] >= 0 &&
FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet)) {
kwsysProcess_ssize_t n;
/* We are handling this pipe now. Remove it from the set. */
FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet);
/* The pipe is ready to read without blocking. Keep trying to
read until the operation is not interrupted. */
while (((n = read(cp->PipeReadEnds[i], cp->PipeBuffer,
KWSYSPE_PIPE_BUFFER_SIZE)) < 0) &&
(errno == EINTR))
;
if (n > 0) {
/* We have data on this pipe. */
if (i == KWSYSPE_PIPE_SIGNAL) {
/* A child process has terminated. */
kwsysProcessDestroy(cp);
} else if (data && length) {
/* Report this data. */
*data = cp->PipeBuffer;
*length = (int)(n);
switch (i) {
case KWSYSPE_PIPE_STDOUT:
wd->PipeId = kwsysProcess_Pipe_STDOUT;
break;
case KWSYSPE_PIPE_STDERR:
wd->PipeId = kwsysProcess_Pipe_STDERR;
break;
}
return 1;
}
} else if (n < 0 && errno == EAGAIN) {
/* No data are really ready. The select call lied. See the
"man select" page on Linux for cases when this occurs. */
} else {
/* We are done reading from this pipe. */
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
--cp->PipesLeft;
}
}
}
/* If we have data, break early. */
if (wd->PipeId) {
return 1;
}
/* Make sure the set is empty (it should always be empty here
anyway). */
FD_ZERO(&cp->PipeSet);
/* Setup a timeout if required. */
if (wd->TimeoutTime.tv_sec < 0) {
timeout = 0;
} else {
timeout = &timeoutLength;
}
if (kwsysProcessGetTimeoutLeft(
&wd->TimeoutTime, wd->User ? wd->UserTimeout : 0, &timeoutLength, 0)) {
/* Timeout has already expired. */
wd->Expired = 1;
return 1;
}
/* Add the pipe reading ends that are still open. */
max = -1;
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
if (cp->PipeReadEnds[i] >= 0) {
FD_SET(cp->PipeReadEnds[i], &cp->PipeSet);
if (cp->PipeReadEnds[i] > max) {
max = cp->PipeReadEnds[i];
}
}
}
/* Make sure we have a non-empty set. */
if (max < 0) {
/* All pipes have closed. Child has terminated. */
return 1;
}
/* Run select to block until data are available. Repeat call
until it is not interrupted. */
while (((numReady = select(max + 1, &cp->PipeSet, 0, 0, timeout)) < 0) &&
(errno == EINTR))
;
/* Check result of select. */
if (numReady == 0) {
/* Select's timeout expired. */
wd->Expired = 1;
return 1;
} else if (numReady < 0) {
/* Select returned an error. Leave the error description in the
pipe buffer. */
strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
/* Kill the children now. */
kwsysProcess_Kill(cp);
cp->Killed = 0;
cp->SelectError = 1;
}
return 0;
#else
/* Poll pipes for data since we do not have select. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
if (cp->PipeReadEnds[i] >= 0) {
const int fd = cp->PipeReadEnds[i];
int n = read(fd, cp->PipeBuffer, KWSYSPE_PIPE_BUFFER_SIZE);
if (n > 0) {
/* We have data on this pipe. */
if (i == KWSYSPE_PIPE_SIGNAL) {
/* A child process has terminated. */
kwsysProcessDestroy(cp);
} else if (data && length) {
/* Report this data. */
*data = cp->PipeBuffer;
*length = n;
switch (i) {
case KWSYSPE_PIPE_STDOUT:
wd->PipeId = kwsysProcess_Pipe_STDOUT;
break;
case KWSYSPE_PIPE_STDERR:
wd->PipeId = kwsysProcess_Pipe_STDERR;
break;
};
}
return 1;
} else if (n == 0) /* EOF */
{
/* We are done reading from this pipe. */
# if defined(__VMS)
if (!cp->CommandsLeft)
# endif
{
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
--cp->PipesLeft;
}
} else if (n < 0) /* error */
{
# if defined(__VMS)
if (!cp->CommandsLeft) {
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
--cp->PipesLeft;
} else
# endif
if ((errno != EINTR) && (errno != EAGAIN)) {
strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
/* Kill the children now. */
kwsysProcess_Kill(cp);
cp->Killed = 0;
cp->SelectError = 1;
return 1;
}
}
}
}
/* If we have data, break early. */
if (wd->PipeId) {
return 1;
}
if (kwsysProcessGetTimeoutLeft(
&wd->TimeoutTime, wd->User ? wd->UserTimeout : 0, &timeoutLength, 1)) {
/* Timeout has already expired. */
wd->Expired = 1;
return 1;
}
/* Sleep a little, try again. */
{
unsigned int msec =
((timeoutLength.tv_sec * 1000) + (timeoutLength.tv_usec / 1000));
if (msec > 100000) {
msec = 100000; /* do not sleep more than 100 milliseconds at a time */
}
kwsysProcess_usleep(msec);
}
return 0;
#endif
}
int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
{
int 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;
}
/* 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 child processes. */
for (prPipe = 0; prPipe < cp->NumberOfCommands; ++prPipe) {
cp->ProcessResults[prPipe].ExitCode = cp->CommandExitCodes[prPipe];
if (WIFEXITED(cp->ProcessResults[prPipe].ExitCode)) {
/* The child exited normally. */
cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Exited;
cp->ProcessResults[prPipe].ExitException = kwsysProcess_Exception_None;
cp->ProcessResults[prPipe].ExitValue =
(int)WEXITSTATUS(cp->ProcessResults[prPipe].ExitCode);
} else if (WIFSIGNALED(cp->ProcessResults[prPipe].ExitCode)) {
/* The child received an unhandled signal. */
cp->ProcessResults[prPipe].State = kwsysProcess_State_Exception;
kwsysProcessSetExitExceptionByIndex(
cp, (int)WTERMSIG(cp->ProcessResults[prPipe].ExitCode), prPipe);
} else {
/* Error getting the child return code. */
strcpy(cp->ProcessResults[prPipe].ExitExceptionString,
"Error getting child return code.");
cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Error;
}
}
/* support legacy state status value */
cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State;
}
/* Normal cleanup. */
kwsysProcessCleanup(cp, 0);
return 1;
}
void kwsysProcess_Interrupt(kwsysProcess* cp)
{
int i;
/* Make sure we are executing a process. */
if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
cp->Killed) {
return;
}
/* Interrupt the children. */
if (cp->CreateProcessGroup) {
if (cp->ForkPIDs) {
for (i = 0; i < cp->NumberOfCommands; ++i) {
/* Make sure the PID is still valid. */
if (cp->ForkPIDs[i]) {
/* The user created a process group for this process. The group ID
is the process ID for the original process in the group. */
kill(-cp->ForkPIDs[i], SIGINT);
}
}
}
} else {
/* No process group was created. Kill our own process group.
NOTE: While one could argue that we could call kill(cp->ForkPIDs[i],
SIGINT) as a way to still interrupt the process even though it's not in
a special group, this is not an option on Windows. Therefore, we kill
the current process group for consistency with Windows. */
kill(0, SIGINT);
}
}
void kwsysProcess_Kill(kwsysProcess* cp)
{
int i;
/* Make sure we are executing a process. */
if (!cp || cp->State != kwsysProcess_State_Executing) {
return;
}
/* First close the child exit report pipe write end to avoid causing a
SIGPIPE when the child terminates and our signal handler tries to
report it after we have already closed the read end. */
kwsysProcessCleanupDescriptor(&cp->SignalPipe);
#if !defined(__APPLE__)
/* Close all the pipe read ends. Do this before killing the
children because Cygwin has problems killing processes that are
blocking to wait for writing to their output pipes. */
kwsysProcessClosePipes(cp);
#endif
/* Kill the children. */
cp->Killed = 1;
for (i = 0; i < cp->NumberOfCommands; ++i) {
int status;
if (cp->ForkPIDs[i]) {
/* Kill the child. */
kwsysProcessKill(cp->ForkPIDs[i]);
/* Reap the child. Keep trying until the call is not
interrupted. */
while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR))
;
}
}
#if defined(__APPLE__)
/* Close all the pipe read ends. Do this after killing the
children because OS X has problems closing pipe read ends whose
pipes are full and still have an open write end. */
kwsysProcessClosePipes(cp);
#endif
cp->CommandsLeft = 0;
}
/* Call the free() function with a pointer to volatile without causing
compiler warnings. */
static void kwsysProcessVolatileFree(volatile void* p)
{
/* clang has made it impossible to free memory that points to volatile
without first using special pragmas to disable a warning... */
#if defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wcast-qual"
#endif
free((void*)p); /* The cast will silence most compilers, but not clang. */
#if defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma clang diagnostic pop
#endif
}
/* Initialize a process control structure for kwsysProcess_Execute. */
static int kwsysProcessInitialize(kwsysProcess* cp)
{
int i;
volatile pid_t* oldForkPIDs;
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
cp->PipeReadEnds[i] = -1;
}
for (i = 0; i < 3; ++i) {
cp->PipeChildStd[i] = -1;
}
cp->SignalPipe = -1;
cp->SelectError = 0;
cp->StartTime.tv_sec = -1;
cp->StartTime.tv_usec = -1;
cp->TimeoutTime.tv_sec = -1;
cp->TimeoutTime.tv_usec = -1;
cp->TimeoutExpired = 0;
cp->PipesLeft = 0;
cp->CommandsLeft = 0;
#if KWSYSPE_USE_SELECT
FD_ZERO(&cp->PipeSet);
#endif
cp->State = kwsysProcess_State_Starting;
cp->Killed = 0;
cp->ErrorMessage[0] = 0;
oldForkPIDs = cp->ForkPIDs;
cp->ForkPIDs = (volatile pid_t*)malloc(sizeof(volatile pid_t) *
(size_t)(cp->NumberOfCommands));
kwsysProcessVolatileFree(oldForkPIDs);
if (!cp->ForkPIDs) {
return 0;
}
for (i = 0; i < cp->NumberOfCommands; ++i) {
cp->ForkPIDs[i] = 0; /* can't use memset due to volatile */
}
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 process result information for each process. */
free(cp->ProcessResults);
cp->ProcessResults = (kwsysProcessResults*)malloc(
sizeof(kwsysProcessResults) * (size_t)(cp->NumberOfCommands));
if (!cp->ProcessResults) {
return 0;
}
memset(cp->ProcessResults, 0,
sizeof(kwsysProcessResults) * (size_t)(cp->NumberOfCommands));
for (i = 0; i < cp->NumberOfCommands; i++) {
cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None;
cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting;
cp->ProcessResults[i].ExitCode = 1;
cp->ProcessResults[i].ExitValue = 1;
strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception");
}
/* Allocate memory to save the real working directory. */
if (cp->WorkingDirectory) {
#if defined(MAXPATHLEN)
cp->RealWorkingDirectoryLength = MAXPATHLEN;
#elif defined(PATH_MAX)
cp->RealWorkingDirectoryLength = PATH_MAX;
#else
cp->RealWorkingDirectoryLength = 4096;
#endif
cp->RealWorkingDirectory =
(char*)malloc((size_t)(cp->RealWorkingDirectoryLength));
if (!cp->RealWorkingDirectory) {
return 0;
}
}
return 1;
}
/* Free all resources used by the given kwsysProcess instance that were
allocated by kwsysProcess_Execute. */
static void kwsysProcessCleanup(kwsysProcess* cp, int error)
{
int i;
if (error) {
/* We are cleaning up due to an error. Report the error message
if one has not been provided already. */
if (cp->ErrorMessage[0] == 0) {
strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
}
/* Set the error state. */
cp->State = kwsysProcess_State_Error;
/* Kill any children already started. */
if (cp->ForkPIDs) {
int status;
for (i = 0; i < cp->NumberOfCommands; ++i) {
if (cp->ForkPIDs[i]) {
/* Kill the child. */
kwsysProcessKill(cp->ForkPIDs[i]);
/* Reap the child. Keep trying until the call is not
interrupted. */
while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) &&
(errno == EINTR))
;
}
}
}
/* Restore the working directory. */
if (cp->RealWorkingDirectory) {
while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR))
;
}
}
/* If not creating a detached child, remove this object from the
global set of process objects that wish to be notified when a
child exits. */
if (!cp->OptionDetach) {
kwsysProcessesRemove(cp);
}
/* Free memory. */
if (cp->ForkPIDs) {
kwsysProcessVolatileFree(cp->ForkPIDs);
cp->ForkPIDs = 0;
}
if (cp->RealWorkingDirectory) {
free(cp->RealWorkingDirectory);
cp->RealWorkingDirectory = 0;
}
/* Close pipe handles. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
}
for (i = 0; i < 3; ++i) {
kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]);
}
}
/* Close the given file descriptor if it is open. Reset its value to -1. */
static void kwsysProcessCleanupDescriptor(int* pfd)
{
if (pfd && *pfd > 2) {
/* Keep trying to close until it is not interrupted by a
* signal. */
while ((close(*pfd) < 0) && (errno == EINTR))
;
*pfd = -1;
}
}
static void kwsysProcessClosePipes(kwsysProcess* cp)
{
int i;
/* Close any pipes that are still open. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
if (cp->PipeReadEnds[i] >= 0) {
#if KWSYSPE_USE_SELECT
/* If the pipe was reported by the last call to select, we must
read from it. This is needed to satisfy the suggestions from
"man select_tut" and is not needed for the polling
implementation. Ignore the data. */
if (FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet)) {
/* We are handling this pipe now. Remove it from the set. */
FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet);
/* The pipe is ready to read without blocking. Keep trying to
read until the operation is not interrupted. */
while ((read(cp->PipeReadEnds[i], cp->PipeBuffer,
KWSYSPE_PIPE_BUFFER_SIZE) < 0) &&
(errno == EINTR))
;
}
#endif
/* We are done reading from this pipe. */
kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]);
--cp->PipesLeft;
}
}
}
static int kwsysProcessSetNonBlocking(int fd)
{
int flags = fcntl(fd, F_GETFL);
if (flags >= 0) {
flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
return flags >= 0;
}
#if defined(__VMS)
int decc$set_child_standard_streams(int fd1, int fd2, int fd3);
#endif
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
kwsysProcessCreateInformation* si)
{
sigset_t mask, old_mask;
int pgidPipe[2];
char tmp;
ssize_t readRes;
/* Create the error reporting pipe. */
if (pipe(si->ErrorPipe) < 0) {
return 0;
}
/* Create a pipe for detecting that the child process has created a process
group and session. */
if (pipe(pgidPipe) < 0) {
kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
return 0;
}
/* Set close-on-exec flag on the pipe's write end. */
if (fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0 ||
fcntl(pgidPipe[1], F_SETFD, FD_CLOEXEC) < 0) {
kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
kwsysProcessCleanupDescriptor(&pgidPipe[0]);
kwsysProcessCleanupDescriptor(&pgidPipe[1]);
return 0;
}
/* Block SIGINT / SIGTERM while we start. The purpose is so that our signal
handler doesn't get called from the child process after the fork and
before the exec, and subsequently start kill()'ing PIDs from ForkPIDs. */
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
kwsysProcessCleanupDescriptor(&pgidPipe[0]);
kwsysProcessCleanupDescriptor(&pgidPipe[1]);
return 0;
}
/* Fork off a child process. */
#if defined(__VMS)
/* VMS needs vfork and execvp to be in the same function because
they use setjmp/longjmp to run the child startup code in the
parent! TODO: OptionDetach. Also
TODO: CreateProcessGroup. */
cp->ForkPIDs[prIndex] = vfork();
#else
cp->ForkPIDs[prIndex] = kwsysProcessFork(cp, si);
#endif
if (cp->ForkPIDs[prIndex] < 0) {
sigprocmask(SIG_SETMASK, &old_mask, 0);
kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
kwsysProcessCleanupDescriptor(&pgidPipe[0]);
kwsysProcessCleanupDescriptor(&pgidPipe[1]);
return 0;
}
if (cp->ForkPIDs[prIndex] == 0) {
#if defined(__VMS)
/* Specify standard pipes for child process. */
decc$set_child_standard_streams(si->StdIn, si->StdOut, si->StdErr);
#else
/* Close the read end of the error reporting / process group
setup pipe. */
close(si->ErrorPipe[0]);
close(pgidPipe[0]);
/* Setup the stdin, stdout, and stderr pipes. */
if (si->StdIn > 0) {
dup2(si->StdIn, 0);
} else if (si->StdIn < 0) {
close(0);
}
if (si->StdOut != 1) {
dup2(si->StdOut, 1);
}
if (si->StdErr != 2) {
dup2(si->StdErr, 2);
}
/* Clear the close-on-exec flag for stdin, stdout, and stderr.
All other pipe handles will be closed when exec succeeds. */
fcntl(0, F_SETFD, 0);
fcntl(1, F_SETFD, 0);
fcntl(2, F_SETFD, 0);
/* Restore all default signal handlers. */
kwsysProcessRestoreDefaultSignalHandlers();
/* Now that we have restored default signal handling and created the
process group, restore mask. */
sigprocmask(SIG_SETMASK, &old_mask, 0);
/* Create new process group. We use setsid instead of setpgid to avoid
the child getting hung up on signals like SIGTTOU. (In the real world,
this has been observed where "git svn" ends up calling the "resize"
program which opens /dev/tty. */
if (cp->CreateProcessGroup && setsid() < 0) {
kwsysProcessChildErrorExit(si->ErrorPipe[1]);
}
#endif
/* Execute the real process. If successful, this does not return. */
execvp(cp->Commands[prIndex][0], cp->Commands[prIndex]);
/* TODO: What does VMS do if the child fails to start? */
/* TODO: On VMS, how do we put the process in a new group? */
/* Failure. Report error to parent and terminate. */
kwsysProcessChildErrorExit(si->ErrorPipe[1]);
}
#if defined(__VMS)
/* Restore the standard pipes of this process. */
decc$set_child_standard_streams(0, 1, 2);
#endif
/* We are done with the error reporting pipe and process group setup pipe
write end. */
kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
kwsysProcessCleanupDescriptor(&pgidPipe[1]);
/* Make sure the child is in the process group before we proceed. This
avoids race conditions with calls to the kill function that we make for
signalling process groups. */
while ((readRes = read(pgidPipe[0], &tmp, 1)) > 0)
;
if (readRes < 0) {
sigprocmask(SIG_SETMASK, &old_mask, 0);
kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
kwsysProcessCleanupDescriptor(&pgidPipe[0]);
return 0;
}
kwsysProcessCleanupDescriptor(&pgidPipe[0]);
/* Unmask signals. */
if (sigprocmask(SIG_SETMASK, &old_mask, 0) < 0) {
kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
return 0;
}
/* A child has been created. */
++cp->CommandsLeft;
/* Block until the child's exec call succeeds and closes the error
pipe or writes data to the pipe to report an error. */
{
kwsysProcess_ssize_t total = 0;
kwsysProcess_ssize_t n = 1;
/* Read the entire error message up to the length of our buffer. */
while (total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0) {
/* Keep trying to read until the operation is not interrupted. */
while (((n = read(si->ErrorPipe[0], cp->ErrorMessage + total,
(size_t)(KWSYSPE_PIPE_BUFFER_SIZE - total))) < 0) &&
(errno == EINTR))
;
if (n > 0) {
total += n;
}
}
/* We are done with the error reporting pipe read end. */
kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
if (total > 0) {
/* The child failed to execute the process. */
return 0;
}
}
return 1;
}
static void kwsysProcessDestroy(kwsysProcess* cp)
{
/* A child process has terminated. Reap it if it is one handled by
this object. */
int i;
/* Temporarily disable signals that access ForkPIDs. We don't want them to
read a reaped PID, and writes to ForkPIDs are not atomic. */
sigset_t mask, old_mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
return;
}
for (i = 0; i < cp->NumberOfCommands; ++i) {
if (cp->ForkPIDs[i]) {
int result;
while (((result = waitpid(cp->ForkPIDs[i], &cp->CommandExitCodes[i],
WNOHANG)) < 0) &&
(errno == EINTR))
;
if (result > 0) {
/* This child has terminated. */
cp->ForkPIDs[i] = 0;
if (--cp->CommandsLeft == 0) {
/* All children have terminated. Close the signal pipe
write end so that no more notifications are sent to this
object. */
kwsysProcessCleanupDescriptor(&cp->SignalPipe);
/* TODO: Once the children have terminated, switch
WaitForData to use a non-blocking read to get the
rest of the data from the pipe. This is needed when
grandchildren keep the output pipes open. */
}
} else if (result < 0 && cp->State != kwsysProcess_State_Error) {
/* Unexpected error. Report the first time this happens. */
strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE);
cp->State = kwsysProcess_State_Error;
}
}
}
/* Re-enable signals. */
sigprocmask(SIG_SETMASK, &old_mask, 0);
}
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
{
int fout;
if (!name) {
return 1;
}
/* Close the existing descriptor. */
kwsysProcessCleanupDescriptor(p);
/* Open a file for the pipe to write. */
if ((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
return 0;
}
/* Set close-on-exec flag on the pipe's end. */
if (fcntl(fout, F_SETFD, FD_CLOEXEC) < 0) {
close(fout);
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;
#if KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC
struct timespec current_timespec;
clock_gettime(CLOCK_MONOTONIC, &current_timespec);
current_native.tv_sec = current_timespec.tv_sec;
current_native.tv_usec = current_timespec.tv_nsec / 1000;
#else
gettimeofday(&current_native, 0);
#endif
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->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \
strcpy(cp->ProcessResults[idx].ExitExceptionString, str)
static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig,
int idx)
{
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->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other;
sprintf(cp->ProcessResults[idx].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);
buffer[KWSYSPE_PIPE_BUFFER_SIZE - 1] = '\0';
/* 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
void kwsysProcess_KillPID(unsigned long process_id)
{
kwsysProcessKill((pid_t)process_id);
}
static void kwsysProcessKill(pid_t process_id)
{
#if defined(__linux__) || defined(__CYGWIN__)
DIR* procdir;
#endif
/* Suspend the process to be sure it will not create more children. */
kill(process_id, SIGSTOP);
#if defined(__CYGWIN__)
/* Some Cygwin versions seem to need help here. Give up our time slice
so that the child can process SIGSTOP before we send SIGKILL. */
usleep(1);
#endif
/* Kill all children if we can find them. */
#if defined(__linux__) || defined(__CYGWIN__)
/* First try using the /proc filesystem. */
if ((procdir = opendir("/proc")) != NULL) {
# if defined(MAXPATHLEN)
char fname[MAXPATHLEN];
# elif defined(PATH_MAX)
char fname[PATH_MAX];
# else
char fname[4096];
# endif
char buffer[KWSYSPE_PIPE_BUFFER_SIZE + 1];
struct dirent* d;
/* Each process has a directory in /proc whose name is the pid.
Within this directory is a file called stat that has the
following format:
pid (command line) status ppid ...
We want to get the ppid for all processes. Those that have
process_id as their parent should be recursively killed. */
for (d = readdir(procdir); d; d = readdir(procdir)) {
int pid;
if (sscanf(d->d_name, "%d", &pid) == 1 && pid != 0) {
struct stat finfo;
sprintf(fname, "/proc/%d/stat", pid);
if (stat(fname, &finfo) == 0) {
FILE* f = fopen(fname, "r");
if (f) {
size_t nread = fread(buffer, 1, KWSYSPE_PIPE_BUFFER_SIZE, f);
fclose(f);
buffer[nread] = '\0';
if (nread > 0) {
const char* rparen = strrchr(buffer, ')');
int ppid;
if (rparen && (sscanf(rparen + 1, "%*s %d", &ppid) == 1)) {
if (ppid == process_id) {
/* Recursively kill this child and its children. */
kwsysProcessKill(pid);
}
}
}
}
}
}
}
closedir(procdir);
} else
#endif
{
#if defined(KWSYSPE_PS_COMMAND)
/* Try running "ps" to get the process information. */
FILE* ps = popen(KWSYSPE_PS_COMMAND, "r");
/* Make sure the process started and provided a valid header. */
if (ps && fscanf(ps, "%*[^\n]\n") != EOF) {
/* Look for processes whose parent is the process being killed. */
int pid, ppid;
while (fscanf(ps, KWSYSPE_PS_FORMAT, &pid, &ppid) == 2) {
if (ppid == process_id) {
/* Recursively kill this child and its children. */
kwsysProcessKill(pid);
}
}
}
/* We are done with the ps process. */
if (ps) {
pclose(ps);
}
#endif
}
/* Kill the process. */
kill(process_id, SIGKILL);
#if defined(__APPLE__)
/* On OS X 10.3 the above SIGSTOP occasionally prevents the SIGKILL
from working. Just in case, we resume the child and kill it
again. There is a small race condition in this obscure case. If
the child manages to fork again between these two signals, we
will not catch its children. */
kill(process_id, SIGCONT);
kill(process_id, SIGKILL);
#endif
}
#if defined(__VMS)
int decc$feature_get_index(const char* name);
int decc$feature_set_value(int index, int mode, int value);
static int kwsysProcessSetVMSFeature(const char* name, int value)
{
int i;
errno = 0;
i = decc$feature_get_index(name);
return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0);
}
#endif
/* Global set of executing processes for use by the signal handler.
This global instance will be zero-initialized by the compiler. */
typedef struct kwsysProcessInstances_s
{
int Count;
int Size;
kwsysProcess** Processes;
} kwsysProcessInstances;
static kwsysProcessInstances kwsysProcesses;
/* The old SIGCHLD / SIGINT / SIGTERM handlers. */
static struct sigaction kwsysProcessesOldSigChldAction;
static struct sigaction kwsysProcessesOldSigIntAction;
static struct sigaction kwsysProcessesOldSigTermAction;
static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses)
{
/* Block signals while we update the set of pipes to check.
TODO: sigprocmask is undefined for threaded apps. See
pthread_sigmask. */
sigset_t newset;
sigset_t oldset;
sigemptyset(&newset);
sigaddset(&newset, SIGCHLD);
sigaddset(&newset, SIGINT);
sigaddset(&newset, SIGTERM);
sigprocmask(SIG_BLOCK, &newset, &oldset);
/* Store the new set in that seen by the signal handler. */
kwsysProcesses = *newProcesses;
/* Restore the signal mask to the previous setting. */
sigprocmask(SIG_SETMASK, &oldset, 0);
}
static int kwsysProcessesAdd(kwsysProcess* cp)
{
/* Create a pipe through which the signal handler can notify the
given process object that a child has exited. */
{
/* Create the pipe. */
int p[2];
if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) {
return 0;
}
/* Store the pipes now to be sure they are cleaned up later. */
cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL] = p[0];
cp->SignalPipe = p[1];
/* Switch the pipe to non-blocking mode so that reading a byte can
be an atomic test-and-set. */
if (!kwsysProcessSetNonBlocking(p[0]) ||
!kwsysProcessSetNonBlocking(p[1])) {
return 0;
}
/* The children do not need this pipe. Set close-on-exec flag on
the pipe's ends. */
if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) ||
(fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) {
return 0;
}
}
/* Attempt to add the given signal pipe to the signal handler set. */
{
/* Make sure there is enough space for the new signal pipe. */
kwsysProcessInstances oldProcesses = kwsysProcesses;
kwsysProcessInstances newProcesses = oldProcesses;
if (oldProcesses.Count == oldProcesses.Size) {
/* Start with enough space for a small number of process instances
and double the size each time more is needed. */
newProcesses.Size = oldProcesses.Size ? oldProcesses.Size * 2 : 4;
/* Try allocating the new block of memory. */
if ((newProcesses.Processes = ((kwsysProcess**)malloc(
(size_t)(newProcesses.Size) * sizeof(kwsysProcess*))))) {
/* Copy the old pipe set to the new memory. */
if (oldProcesses.Count > 0) {
memcpy(newProcesses.Processes, oldProcesses.Processes,
((size_t)(oldProcesses.Count) * sizeof(kwsysProcess*)));
}
} else {
/* Failed to allocate memory for the new signal pipe set. */
return 0;
}
}
/* Append the new signal pipe to the set. */
newProcesses.Processes[newProcesses.Count++] = cp;
/* Store the new set in that seen by the signal handler. */
kwsysProcessesUpdate(&newProcesses);
/* Free the original pipes if new ones were allocated. */
if (newProcesses.Processes != oldProcesses.Processes) {
free(oldProcesses.Processes);
}
/* If this is the first process, enable the signal handler. */
if (newProcesses.Count == 1) {
/* Install our handler for SIGCHLD. Repeat call until it is not
interrupted. */
struct sigaction newSigAction;
memset(&newSigAction, 0, sizeof(struct sigaction));
#if KWSYSPE_USE_SIGINFO
newSigAction.sa_sigaction = kwsysProcessesSignalHandler;
newSigAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
# ifdef SA_RESTART
newSigAction.sa_flags |= SA_RESTART;
# endif
#else
newSigAction.sa_handler = kwsysProcessesSignalHandler;
newSigAction.sa_flags = SA_NOCLDSTOP;
#endif
sigemptyset(&newSigAction.sa_mask);
while ((sigaction(SIGCHLD, &newSigAction,
&kwsysProcessesOldSigChldAction) < 0) &&
(errno == EINTR))
;
/* Install our handler for SIGINT / SIGTERM. Repeat call until
it is not interrupted. */
sigemptyset(&newSigAction.sa_mask);
sigaddset(&newSigAction.sa_mask, SIGTERM);
while ((sigaction(SIGINT, &newSigAction,
&kwsysProcessesOldSigIntAction) < 0) &&
(errno == EINTR))
;
sigemptyset(&newSigAction.sa_mask);
sigaddset(&newSigAction.sa_mask, SIGINT);
while ((sigaction(SIGTERM, &newSigAction,
&kwsysProcessesOldSigIntAction) < 0) &&
(errno == EINTR))
;
}
}
return 1;
}
static void kwsysProcessesRemove(kwsysProcess* cp)
{
/* Attempt to remove the given signal pipe from the signal handler set. */
{
/* Find the given process in the set. */
kwsysProcessInstances newProcesses = kwsysProcesses;
int i;
for (i = 0; i < newProcesses.Count; ++i) {
if (newProcesses.Processes[i] == cp) {
break;
}
}
if (i < newProcesses.Count) {
/* Remove the process from the set. */
--newProcesses.Count;
for (; i < newProcesses.Count; ++i) {
newProcesses.Processes[i] = newProcesses.Processes[i + 1];
}
/* If this was the last process, disable the signal handler. */
if (newProcesses.Count == 0) {
/* Restore the signal handlers. Repeat call until it is not
interrupted. */
while ((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) &&
(errno == EINTR))
;
while ((sigaction(SIGINT, &kwsysProcessesOldSigIntAction, 0) < 0) &&
(errno == EINTR))
;
while ((sigaction(SIGTERM, &kwsysProcessesOldSigTermAction, 0) < 0) &&
(errno == EINTR))
;
/* Free the table of process pointers since it is now empty.
This is safe because the signal handler has been removed. */
newProcesses.Size = 0;
free(newProcesses.Processes);
newProcesses.Processes = 0;
}
/* Store the new set in that seen by the signal handler. */
kwsysProcessesUpdate(&newProcesses);
}
}
/* Close the pipe through which the signal handler may have notified
the given process object that a child has exited. */
kwsysProcessCleanupDescriptor(&cp->SignalPipe);
}
static void kwsysProcessesSignalHandler(int signum
#if KWSYSPE_USE_SIGINFO
,
siginfo_t* info, void* ucontext
#endif
)
{
int i, j, procStatus, old_errno = errno;
#if KWSYSPE_USE_SIGINFO
(void)info;
(void)ucontext;
#endif
/* Signal all process objects that a child has terminated. */
switch (signum) {
case SIGCHLD:
for (i = 0; i < kwsysProcesses.Count; ++i) {
/* Set the pipe in a signalled state. */
char buf = 1;
kwsysProcess* cp = kwsysProcesses.Processes[i];
kwsysProcess_ssize_t pipeStatus =
read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1);
(void)pipeStatus;
pipeStatus = write(cp->SignalPipe, &buf, 1);
(void)pipeStatus;
}
break;
case SIGINT:
case SIGTERM:
/* Signal child processes that are running in new process groups. */
for (i = 0; i < kwsysProcesses.Count; ++i) {
kwsysProcess* cp = kwsysProcesses.Processes[i];
/* Check Killed to avoid data race condition when killing.
Check State to avoid data race condition in kwsysProcessCleanup
when there is an error (it leaves a reaped PID). */
if (cp->CreateProcessGroup && !cp->Killed &&
cp->State != kwsysProcess_State_Error && cp->ForkPIDs) {
for (j = 0; j < cp->NumberOfCommands; ++j) {
/* Make sure the PID is still valid. */
if (cp->ForkPIDs[j]) {
/* The user created a process group for this process. The group
ID
is the process ID for the original process in the group. */
kill(-cp->ForkPIDs[j], SIGINT);
}
}
}
}
/* Wait for all processes to terminate. */
while (wait(&procStatus) >= 0 || errno != ECHILD) {
}
/* Terminate the process, which is now in an inconsistent state
because we reaped all the PIDs that it may have been reaping
or may have reaped in the future. Reraise the signal so that
the proper exit code is returned. */
{
/* Install default signal handler. */
struct sigaction defSigAction;
sigset_t unblockSet;
memset(&defSigAction, 0, sizeof(defSigAction));
defSigAction.sa_handler = SIG_DFL;
sigemptyset(&defSigAction.sa_mask);
while ((sigaction(signum, &defSigAction, 0) < 0) && (errno == EINTR))
;
/* Unmask the signal. */
sigemptyset(&unblockSet);
sigaddset(&unblockSet, signum);
sigprocmask(SIG_UNBLOCK, &unblockSet, 0);
/* Raise the signal again. */
raise(signum);
/* We shouldn't get here... but if we do... */
_exit(1);
}
/* break omitted to silence unreachable code clang compiler warning. */
}
#if !KWSYSPE_USE_SIGINFO
/* Re-Install our handler. Repeat call until it is not interrupted. */
{
struct sigaction newSigAction;
struct sigaction& oldSigAction;
memset(&newSigAction, 0, sizeof(struct sigaction));
newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
newSigChldAction.sa_flags = SA_NOCLDSTOP;
sigemptyset(&newSigAction.sa_mask);
switch (signum) {
case SIGCHLD:
oldSigAction = &kwsysProcessesOldSigChldAction;
break;
case SIGINT:
sigaddset(&newSigAction.sa_mask, SIGTERM);
oldSigAction = &kwsysProcessesOldSigIntAction;
break;
case SIGTERM:
sigaddset(&newSigAction.sa_mask, SIGINT);
oldSigAction = &kwsysProcessesOldSigTermAction;
break;
default:
return 0;
}
while ((sigaction(signum, &newSigAction, oldSigAction) < 0) &&
(errno == EINTR))
;
}
#endif
errno = old_errno;
}
void kwsysProcess_ResetStartTime(kwsysProcess* cp)
{
if (!cp) {
return;
}
/* Reset start time. */
cp->StartTime = kwsysProcessTimeGetCurrent();
}
-2786
View File
@@ -1,2786 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Process.h)
#include KWSYS_HEADER(Encoding.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
#if 0
# include "Encoding.h.in"
# include "Process.h.in"
#endif
/*
Implementation for Windows
On windows, a thread is created to wait for data on each pipe. The
threads are synchronized with the main thread to simulate the use of
a UNIX-style select system call.
*/
#ifdef _MSC_VER
# pragma warning(push, 1)
#endif
#include <windows.h> /* Windows API */
#if defined(_MSC_VER) && _MSC_VER >= 1800
# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
#endif
#include <io.h> /* _unlink */
#include <stdio.h> /* sprintf */
#include <string.h> /* strlen, strdup */
#ifdef __WATCOMC__
# define _unlink unlink
#endif
#ifndef _MAX_FNAME
# define _MAX_FNAME 4096
#endif
#ifndef _MAX_PATH
# define _MAX_PATH 4096
#endif
#ifdef _MSC_VER
# pragma warning(pop)
# pragma warning(disable : 4514)
# pragma warning(disable : 4706)
#endif
#if defined(__BORLANDC__)
# pragma warn - 8004 /* assigned a value that is never used */
# pragma warn - 8060 /* Assignment inside if() condition. */
#endif
/* There are pipes for the process pipeline's stdout and stderr. */
#define KWSYSPE_PIPE_COUNT 2
#define KWSYSPE_PIPE_STDOUT 0
#define KWSYSPE_PIPE_STDERR 1
/* The maximum amount to read from a pipe at a time. */
#define KWSYSPE_PIPE_BUFFER_SIZE 1024
/* Debug output macro. */
#if 0
# define KWSYSPE_DEBUG(x) \
((void*)cp == (void*)0x00226DE0 \
? (fprintf(stderr, "%d/%p/%d ", (int)GetCurrentProcessId(), cp, \
__LINE__), \
fprintf x, fflush(stderr), 1) \
: (1))
#else
# define KWSYSPE_DEBUG(x) (void)1
#endif
typedef LARGE_INTEGER kwsysProcessTime;
typedef struct kwsysProcessCreateInformation_s
{
/* Windows child startup control data. */
STARTUPINFOW StartupInfo;
/* Original handles before making inherited duplicates. */
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} kwsysProcessCreateInformation;
typedef struct kwsysProcessPipeData_s kwsysProcessPipeData;
static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd);
static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp,
kwsysProcessPipeData* td);
static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd);
static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp,
kwsysProcessPipeData* td);
static int kwsysProcessInitialize(kwsysProcess* cp);
static DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
kwsysProcessCreateInformation* si);
static void kwsysProcessDestroy(kwsysProcess* cp, int event);
static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle);
static void kwsysProcessCleanupHandle(PHANDLE h);
static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error);
static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime);
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
double* userTimeout,
kwsysProcessTime* timeoutLength);
static kwsysProcessTime kwsysProcessTimeGetCurrent(void);
static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t);
static double kwsysProcessTimeToDouble(kwsysProcessTime t);
static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
kwsysProcessTime in2);
static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
kwsysProcessTime in2);
static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code,
int idx);
static void kwsysProcessKillTree(int pid);
static void kwsysProcessDisablePipeThreads(kwsysProcess* cp);
static int kwsysProcessesInitialize(void);
static int kwsysTryEnterCreateProcessSection(void);
static void kwsysLeaveCreateProcessSection(void);
static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId,
int newProcessGroup);
static void kwsysProcessesRemove(HANDLE hProcess);
static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType);
/* A structure containing synchronization data for each thread. */
typedef struct kwsysProcessPipeSync_s kwsysProcessPipeSync;
struct kwsysProcessPipeSync_s
{
/* Handle to the thread. */
HANDLE Thread;
/* Semaphore indicating to the thread that a process has started. */
HANDLE Ready;
/* Semaphore indicating to the thread that it should begin work. */
HANDLE Go;
/* Semaphore indicating thread has reset for another process. */
HANDLE Reset;
};
/* A structure containing data for each pipe's threads. */
struct kwsysProcessPipeData_s
{
/* ------------- Data managed per instance of kwsysProcess ------------- */
/* Synchronization data for reading thread. */
kwsysProcessPipeSync Reader;
/* Synchronization data for waking thread. */
kwsysProcessPipeSync Waker;
/* Index of this pipe. */
int Index;
/* The kwsysProcess instance owning this pipe. */
kwsysProcess* Process;
/* ------------- Data managed per call to Execute ------------- */
/* Buffer for data read in this pipe's thread. */
char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
/* The length of the data stored in the buffer. */
DWORD DataLength;
/* Whether the pipe has been closed. */
int Closed;
/* Handle for the read end of this pipe. */
HANDLE Read;
/* Handle for the write end of this pipe. */
HANDLE Write;
};
/* A structure containing results data for each process. */
typedef struct kwsysProcessResults_s kwsysProcessResults;
struct kwsysProcessResults_s
{
/* The status of the process. */
int State;
/* 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;
/* Description for the ExitException. */
char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1];
};
/* Structure containing data used to implement the child's execution. */
struct kwsysProcess_s
{
/* ------------- Data managed per instance of kwsysProcess ------------- */
/* The status of the process structure. */
int State;
/* The command lines to execute. */
wchar_t** Commands;
int NumberOfCommands;
/* The exit code of each command. */
DWORD* CommandExitCodes;
/* The working directory for the child process. */
wchar_t* WorkingDirectory;
/* Whether to create the child as a detached process. */
int OptionDetach;
/* Whether the child was created as a detached process. */
int Detached;
/* Whether to hide the child process's window. */
int HideWindow;
/* Whether to treat command lines as verbatim. */
int Verbatim;
/* Whether to merge stdout/stderr of the child. */
int MergeOutput;
/* Whether to create the process in a new process group. */
int CreateProcessGroup;
/* Mutex to protect the shared index used by threads to report data. */
HANDLE SharedIndexMutex;
/* Semaphore used by threads to signal data ready. */
HANDLE Full;
/* Whether we are currently deleting this kwsysProcess instance. */
int Deleting;
/* Data specific to each pipe and its thread. */
kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT];
/* Name of files to which stdin and stdout pipes are attached. */
char* PipeFileSTDIN;
char* PipeFileSTDOUT;
char* PipeFileSTDERR;
/* Whether each pipe is shared with the parent process. */
int PipeSharedSTDIN;
int PipeSharedSTDOUT;
int PipeSharedSTDERR;
/* Native pipes provided by the user. */
HANDLE PipeNativeSTDIN[2];
HANDLE PipeNativeSTDOUT[2];
HANDLE PipeNativeSTDERR[2];
/* ------------- Data managed per call to Execute ------------- */
/* Index of last pipe to report data, if any. */
int CurrentIndex;
/* Index shared by threads to report data. */
int SharedIndex;
/* The timeout length. */
double Timeout;
/* Time at which the child started. */
kwsysProcessTime StartTime;
/* Time at which the child will timeout. Negative for no timeout. */
kwsysProcessTime TimeoutTime;
/* Flag for whether the process was killed. */
int Killed;
/* Flag for whether the timeout expired. */
int TimeoutExpired;
/* Flag for whether the process has terminated. */
int Terminated;
/* The number of pipes still open during execution and while waiting
for pipes to close after process termination. */
int PipesLeft;
/* Buffer for error messages. */
char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1];
/* process results. */
kwsysProcessResults* ProcessResults;
/* Windows process information data. */
PROCESS_INFORMATION* ProcessInformation;
/* Data and process termination events for which to wait. */
PHANDLE ProcessEvents;
int ProcessEventsLength;
/* Real working directory of our own process. */
DWORD RealWorkingDirectoryLength;
wchar_t* RealWorkingDirectory;
/* Own handles for the child's ends of the pipes in the parent process.
Used temporarily during process creation. */
HANDLE PipeChildStd[3];
};
kwsysProcess* kwsysProcess_New(void)
{
int i;
/* Process control structure. */
kwsysProcess* cp;
/* Windows version number data. */
OSVERSIONINFO osv;
/* Initialize list of processes before we get any farther. It's especially
important that the console Ctrl handler be added BEFORE starting the
first process. This prevents the risk of an orphaned process being
started by the main thread while the default Ctrl handler is in
progress. */
if (!kwsysProcessesInitialize()) {
return 0;
}
/* Allocate a process control structure. */
cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
if (!cp) {
/* Could not allocate memory for the control structure. */
return 0;
}
ZeroMemory(cp, sizeof(*cp));
/* Share stdin with the parent process by default. */
cp->PipeSharedSTDIN = 1;
/* Set initial status. */
cp->State = kwsysProcess_State_Starting;
/* Choose a method of running the child based on version of
windows. */
ZeroMemory(&osv, sizeof(osv));
osv.dwOSVersionInfoSize = sizeof(osv);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
# elif defined __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
#endif
GetVersionEx(&osv);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# ifdef __clang__
# pragma clang diagnostic pop
# else
# pragma warning(pop)
# endif
#endif
if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
/* Win9x no longer supported. */
kwsysProcess_Delete(cp);
return 0;
}
/* Initially no thread owns the mutex. Initialize semaphore to 1. */
if (!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0))) {
kwsysProcess_Delete(cp);
return 0;
}
/* Initially no data are available. Initialize semaphore to 0. */
if (!(cp->Full = CreateSemaphore(0, 0, 1, 0))) {
kwsysProcess_Delete(cp);
return 0;
}
/* Create the thread to read each pipe. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
DWORD dummy = 0;
/* Assign the thread its index. */
cp->Pipe[i].Index = i;
/* Give the thread a pointer back to the kwsysProcess instance. */
cp->Pipe[i].Process = cp;
/* No process is yet running. Initialize semaphore to 0. */
if (!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0))) {
kwsysProcess_Delete(cp);
return 0;
}
/* The pipe is not yet reset. Initialize semaphore to 0. */
if (!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0))) {
kwsysProcess_Delete(cp);
return 0;
}
/* The thread's buffer is initially empty. Initialize semaphore to 1. */
if (!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0))) {
kwsysProcess_Delete(cp);
return 0;
}
/* Create the reading thread. It will block immediately. The
thread will not make deeply nested calls, so we need only a
small stack. */
if (!(cp->Pipe[i].Reader.Thread = CreateThread(
0, 1024, kwsysProcessPipeThreadRead, &cp->Pipe[i], 0, &dummy))) {
kwsysProcess_Delete(cp);
return 0;
}
/* No process is yet running. Initialize semaphore to 0. */
if (!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0))) {
kwsysProcess_Delete(cp);
return 0;
}
/* The pipe is not yet reset. Initialize semaphore to 0. */
if (!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0))) {
kwsysProcess_Delete(cp);
return 0;
}
/* The waker should not wake immediately. Initialize semaphore to 0. */
if (!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0))) {
kwsysProcess_Delete(cp);
return 0;
}
/* Create the waking thread. It will block immediately. The
thread will not make deeply nested calls, so we need only a
small stack. */
if (!(cp->Pipe[i].Waker.Thread = CreateThread(
0, 1024, kwsysProcessPipeThreadWake, &cp->Pipe[i], 0, &dummy))) {
kwsysProcess_Delete(cp);
return 0;
}
}
for (i = 0; i < 3; ++i) {
cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
}
return cp;
}
void kwsysProcess_Delete(kwsysProcess* cp)
{
int i;
/* Make sure we have an instance. */
if (!cp) {
return;
}
/* If the process is executing, wait for it to finish. */
if (cp->State == kwsysProcess_State_Executing) {
if (cp->Detached) {
kwsysProcess_Disown(cp);
} else {
kwsysProcess_WaitForExit(cp, 0);
}
}
/* We are deleting the kwsysProcess instance. */
cp->Deleting = 1;
/* Terminate each of the threads. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
/* Terminate this reading thread. */
if (cp->Pipe[i].Reader.Thread) {
/* Signal the thread we are ready for it. It will terminate
immediately since Deleting is set. */
ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
/* Wait for the thread to exit. */
WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE);
/* Close the handle to the thread. */
kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread);
}
/* Terminate this waking thread. */
if (cp->Pipe[i].Waker.Thread) {
/* Signal the thread we are ready for it. It will terminate
immediately since Deleting is set. */
ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
/* Wait for the thread to exit. */
WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE);
/* Close the handle to the thread. */
kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread);
}
/* Cleanup the pipe's semaphores. */
kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Ready);
kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Go);
kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Reset);
kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Ready);
kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Go);
kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Reset);
}
/* Close the shared semaphores. */
kwsysProcessCleanupHandle(&cp->SharedIndexMutex);
kwsysProcessCleanupHandle(&cp->Full);
/* Free memory. */
kwsysProcess_SetCommand(cp, 0);
kwsysProcess_SetWorkingDirectory(cp, 0);
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
free(cp->CommandExitCodes);
free(cp->ProcessResults);
free(cp);
}
int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
{
int i;
if (!cp) {
return 0;
}
for (i = 0; i < cp->NumberOfCommands; ++i) {
free(cp->Commands[i]);
}
cp->NumberOfCommands = 0;
if (cp->Commands) {
free(cp->Commands);
cp->Commands = 0;
}
if (command) {
return kwsysProcess_AddCommand(cp, command);
}
return 1;
}
int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
{
int newNumberOfCommands;
wchar_t** newCommands;
/* Make sure we have a command to add. */
if (!cp || !command || !*command) {
return 0;
}
/* Allocate a new array for command pointers. */
newNumberOfCommands = cp->NumberOfCommands + 1;
if (!(newCommands =
(wchar_t**)malloc(sizeof(wchar_t*) * newNumberOfCommands))) {
/* Out of memory. */
return 0;
}
/* Copy any existing commands into the new array. */
{
int i;
for (i = 0; i < cp->NumberOfCommands; ++i) {
newCommands[i] = cp->Commands[i];
}
}
if (cp->Verbatim) {
/* Copy the verbatim command line into the buffer. */
newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(*command);
} else {
/* Encode the arguments so CommandLineToArgvW can decode
them from the command line string in the child. */
char buffer[32768]; /* CreateProcess max command-line length. */
char* end = buffer + sizeof(buffer);
char* out = buffer;
char const* const* a;
for (a = command; *a; ++a) {
int quote = !**a; /* Quote the empty string. */
int slashes = 0;
char const* c;
if (a != command && out != end) {
*out++ = ' ';
}
for (c = *a; !quote && *c; ++c) {
quote = (*c == ' ' || *c == '\t');
}
if (quote && out != end) {
*out++ = '"';
}
for (c = *a; *c; ++c) {
if (*c == '\\') {
++slashes;
} else {
if (*c == '"') {
// Add n+1 backslashes to total 2n+1 before internal '"'.
while (slashes-- >= 0 && out != end) {
*out++ = '\\';
}
}
slashes = 0;
}
if (out != end) {
*out++ = *c;
}
}
if (quote) {
// Add n backslashes to total 2n before ending '"'.
while (slashes-- > 0 && out != end) {
*out++ = '\\';
}
if (out != end) {
*out++ = '"';
}
}
}
if (out != end) {
*out = '\0';
newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(buffer);
} else {
newCommands[cp->NumberOfCommands] = 0;
}
}
if (!newCommands[cp->NumberOfCommands]) {
/* Out of memory or command line too long. */
free(newCommands);
return 0;
}
/* Save the new array of commands. */
free(cp->Commands);
cp->Commands = newCommands;
cp->NumberOfCommands = newNumberOfCommands;
return 1;
}
void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
{
if (!cp) {
return;
}
cp->Timeout = timeout;
if (cp->Timeout < 0) {
cp->Timeout = 0;
}
// Force recomputation of TimeoutTime.
cp->TimeoutTime.QuadPart = -1;
}
int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
{
if (!cp) {
return 0;
}
if (cp->WorkingDirectory) {
free(cp->WorkingDirectory);
cp->WorkingDirectory = 0;
}
if (dir && dir[0]) {
wchar_t* wdir = kwsysEncoding_DupToWide(dir);
/* We must convert the working directory to a full path. */
DWORD length = GetFullPathNameW(wdir, 0, 0, 0);
if (length > 0) {
wchar_t* work_dir = malloc(length * sizeof(wchar_t));
if (!work_dir) {
free(wdir);
return 0;
}
if (!GetFullPathNameW(wdir, length, work_dir, 0)) {
free(work_dir);
free(wdir);
return 0;
}
cp->WorkingDirectory = work_dir;
}
free(wdir);
}
return 1;
}
int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
{
char** pfile;
if (!cp) {
return 0;
}
switch (pipe) {
case kwsysProcess_Pipe_STDIN:
pfile = &cp->PipeFileSTDIN;
break;
case kwsysProcess_Pipe_STDOUT:
pfile = &cp->PipeFileSTDOUT;
break;
case kwsysProcess_Pipe_STDERR:
pfile = &cp->PipeFileSTDERR;
break;
default:
return 0;
}
if (*pfile) {
free(*pfile);
*pfile = 0;
}
if (file) {
*pfile = strdup(file);
if (!*pfile) {
return 0;
}
}
/* If we are redirecting the pipe, do not share it or use a native
pipe. */
if (*pfile) {
kwsysProcess_SetPipeNative(cp, pipe, 0);
kwsysProcess_SetPipeShared(cp, pipe, 0);
}
return 1;
}
void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
{
if (!cp) {
return;
}
switch (pipe) {
case kwsysProcess_Pipe_STDIN:
cp->PipeSharedSTDIN = shared ? 1 : 0;
break;
case kwsysProcess_Pipe_STDOUT:
cp->PipeSharedSTDOUT = shared ? 1 : 0;
break;
case kwsysProcess_Pipe_STDERR:
cp->PipeSharedSTDERR = shared ? 1 : 0;
break;
default:
return;
}
/* If we are sharing the pipe, do not redirect it to a file or use a
native pipe. */
if (shared) {
kwsysProcess_SetPipeFile(cp, pipe, 0);
kwsysProcess_SetPipeNative(cp, pipe, 0);
}
}
void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, HANDLE p[2])
{
HANDLE* pPipeNative = 0;
if (!cp) {
return;
}
switch (pipe) {
case kwsysProcess_Pipe_STDIN:
pPipeNative = cp->PipeNativeSTDIN;
break;
case kwsysProcess_Pipe_STDOUT:
pPipeNative = cp->PipeNativeSTDOUT;
break;
case kwsysProcess_Pipe_STDERR:
pPipeNative = cp->PipeNativeSTDERR;
break;
default:
return;
}
/* Copy the native pipe handles provided. */
if (p) {
pPipeNative[0] = p[0];
pPipeNative[1] = p[1];
} else {
pPipeNative[0] = 0;
pPipeNative[1] = 0;
}
/* If we are using a native pipe, do not share it or redirect it to
a file. */
if (p) {
kwsysProcess_SetPipeFile(cp, pipe, 0);
kwsysProcess_SetPipeShared(cp, pipe, 0);
}
}
int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
{
if (!cp) {
return 0;
}
switch (optionId) {
case kwsysProcess_Option_Detach:
return cp->OptionDetach;
case kwsysProcess_Option_HideWindow:
return cp->HideWindow;
case kwsysProcess_Option_MergeOutput:
return cp->MergeOutput;
case kwsysProcess_Option_Verbatim:
return cp->Verbatim;
case kwsysProcess_Option_CreateProcessGroup:
return cp->CreateProcessGroup;
default:
return 0;
}
}
void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
{
if (!cp) {
return;
}
switch (optionId) {
case kwsysProcess_Option_Detach:
cp->OptionDetach = value;
break;
case kwsysProcess_Option_HideWindow:
cp->HideWindow = value;
break;
case kwsysProcess_Option_MergeOutput:
cp->MergeOutput = value;
break;
case kwsysProcess_Option_Verbatim:
cp->Verbatim = value;
break;
case kwsysProcess_Option_CreateProcessGroup:
cp->CreateProcessGroup = value;
break;
default:
break;
}
}
int kwsysProcess_GetState(kwsysProcess* cp)
{
return cp ? cp->State : kwsysProcess_State_Error;
}
int kwsysProcess_GetExitException(kwsysProcess* cp)
{
return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException
: kwsysProcess_Exception_Other;
}
int kwsysProcess_GetExitValue(kwsysProcess* cp)
{
return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue
: -1;
}
int kwsysProcess_GetExitCode(kwsysProcess* cp)
{
return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
? cp->ProcessResults[cp->NumberOfCommands - 1].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 && cp->ProcessResults && (cp->NumberOfCommands > 0))) {
return "GetExceptionString called with NULL process management structure";
} else if (cp->State == kwsysProcess_State_Exception) {
return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString;
}
return "No exception";
}
/* the index should be in array bound. */
#define KWSYSPE_IDX_CHK(RET) \
if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \
KWSYSPE_DEBUG((stderr, "array index out of bound\n")); \
return RET; \
}
int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK(kwsysProcess_State_Error)
return cp->ProcessResults[idx].State;
}
int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other)
return cp->ProcessResults[idx].ExitException;
}
int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK(-1)
return cp->ProcessResults[idx].ExitValue;
}
int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK(-1)
return cp->CommandExitCodes[idx];
}
const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx)
{
KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management "
"structure or index out of bound")
if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) {
return cp->ProcessResults[idx].ExitExceptionString;
}
return "No exception";
}
#undef KWSYSPE_IDX_CHK
void kwsysProcess_Execute(kwsysProcess* cp)
{
int i;
/* Do not execute a second time. */
if (!cp || cp->State == kwsysProcess_State_Executing) {
return;
}
/* Make sure we have something to run. */
if (cp->NumberOfCommands < 1) {
strcpy(cp->ErrorMessage, "No command");
cp->State = kwsysProcess_State_Error;
return;
}
/* Initialize the control structure for a new process. */
if (!kwsysProcessInitialize(cp)) {
strcpy(cp->ErrorMessage, "Out of memory");
cp->State = kwsysProcess_State_Error;
return;
}
/* Save the real working directory of this process and change to
the working directory for the child processes. This is needed
to make pipe file paths evaluate correctly. */
if (cp->WorkingDirectory) {
if (!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength,
cp->RealWorkingDirectory)) {
kwsysProcessCleanup(cp, GetLastError());
return;
}
SetCurrentDirectoryW(cp->WorkingDirectory);
}
/* Setup the stdin pipe for the first process. */
if (cp->PipeFileSTDIN) {
/* Create a handle to read a file for stdin. */
wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN);
DWORD error;
cp->PipeChildStd[0] =
CreateFileW(wstdin, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
OPEN_EXISTING, 0, 0);
error = GetLastError(); /* Check now in case free changes this. */
free(wstdin);
if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) {
kwsysProcessCleanup(cp, error);
return;
}
} else if (cp->PipeSharedSTDIN) {
/* Share this process's stdin with the child. */
kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]);
} else if (cp->PipeNativeSTDIN[0]) {
/* Use the provided native pipe. */
kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]);
} else {
/* Explicitly give the child no stdin. */
cp->PipeChildStd[0] = INVALID_HANDLE_VALUE;
}
/* Create the output pipe for the last process.
We always create this so the pipe thread can run even if we
do not end up giving the write end to the child below. */
if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read,
&cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0)) {
kwsysProcessCleanup(cp, GetLastError());
return;
}
if (cp->PipeFileSTDOUT) {
/* Use a file for stdout. */
DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
cp->PipeFileSTDOUT);
if (error) {
kwsysProcessCleanup(cp, error);
return;
}
} else if (cp->PipeSharedSTDOUT) {
/* Use the parent stdout. */
kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]);
} else if (cp->PipeNativeSTDOUT[1]) {
/* Use the given handle for stdout. */
kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]);
} else {
/* Use our pipe for stdout. Duplicate the handle since our waker
thread will use the original. Do not make it inherited yet. */
if (!DuplicateHandle(GetCurrentProcess(),
cp->Pipe[KWSYSPE_PIPE_STDOUT].Write,
GetCurrentProcess(), &cp->PipeChildStd[1], 0, FALSE,
DUPLICATE_SAME_ACCESS)) {
kwsysProcessCleanup(cp, GetLastError());
return;
}
}
/* Create stderr pipe to be shared by all processes in the pipeline.
We always create this so the pipe thread can run even if we do not
end up giving the write end to the child below. */
if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
&cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) {
kwsysProcessCleanup(cp, GetLastError());
return;
}
if (cp->PipeFileSTDERR) {
/* Use a file for stderr. */
DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
cp->PipeFileSTDERR);
if (error) {
kwsysProcessCleanup(cp, error);
return;
}
} else if (cp->PipeSharedSTDERR) {
/* Use the parent stderr. */
kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]);
} else if (cp->PipeNativeSTDERR[1]) {
/* Use the given handle for stderr. */
kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]);
} else {
/* Use our pipe for stderr. Duplicate the handle since our waker
thread will use the original. Do not make it inherited yet. */
if (!DuplicateHandle(GetCurrentProcess(),
cp->Pipe[KWSYSPE_PIPE_STDERR].Write,
GetCurrentProcess(), &cp->PipeChildStd[2], 0, FALSE,
DUPLICATE_SAME_ACCESS)) {
kwsysProcessCleanup(cp, GetLastError());
return;
}
}
/* Create the pipeline of processes. */
{
/* Child startup control data. */
kwsysProcessCreateInformation si;
HANDLE nextStdInput = cp->PipeChildStd[0];
/* Initialize startup info data. */
ZeroMemory(&si, sizeof(si));
si.StartupInfo.cb = sizeof(si.StartupInfo);
/* Decide whether a child window should be shown. */
si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
si.StartupInfo.wShowWindow =
(unsigned short)(cp->HideWindow ? SW_HIDE : SW_SHOWDEFAULT);
/* Connect the child's output pipes to the threads. */
si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
for (i = 0; i < cp->NumberOfCommands; ++i) {
/* Setup the process's pipes. */
si.hStdInput = nextStdInput;
if (i == cp->NumberOfCommands - 1) {
/* The last child gets the overall stdout. */
nextStdInput = INVALID_HANDLE_VALUE;
si.hStdOutput = cp->PipeChildStd[1];
} else {
/* Create a pipe to sit between the children. */
HANDLE p[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
if (!CreatePipe(&p[0], &p[1], 0, 0)) {
DWORD error = GetLastError();
if (nextStdInput != cp->PipeChildStd[0]) {
kwsysProcessCleanupHandle(&nextStdInput);
}
kwsysProcessCleanup(cp, error);
return;
}
nextStdInput = p[0];
si.hStdOutput = p[1];
}
si.hStdError =
cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2];
{
DWORD error = kwsysProcessCreate(cp, i, &si);
/* Close our copies of pipes used between children. */
if (si.hStdInput != cp->PipeChildStd[0]) {
kwsysProcessCleanupHandle(&si.hStdInput);
}
if (si.hStdOutput != cp->PipeChildStd[1]) {
kwsysProcessCleanupHandle(&si.hStdOutput);
}
if (si.hStdError != cp->PipeChildStd[2] && !cp->MergeOutput) {
kwsysProcessCleanupHandle(&si.hStdError);
}
if (!error) {
cp->ProcessEvents[i + 1] = cp->ProcessInformation[i].hProcess;
} else {
if (nextStdInput != cp->PipeChildStd[0]) {
kwsysProcessCleanupHandle(&nextStdInput);
}
kwsysProcessCleanup(cp, error);
return;
}
}
}
}
/* The parent process does not need the child's pipe ends. */
for (i = 0; i < 3; ++i) {
kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
}
/* Restore the working directory. */
if (cp->RealWorkingDirectory) {
SetCurrentDirectoryW(cp->RealWorkingDirectory);
free(cp->RealWorkingDirectory);
cp->RealWorkingDirectory = 0;
}
/* The timeout period starts now. */
cp->StartTime = kwsysProcessTimeGetCurrent();
cp->TimeoutTime = kwsysProcessTimeFromDouble(-1);
/* All processes in the pipeline have been started in suspended
mode. Resume them all now. */
for (i = 0; i < cp->NumberOfCommands; ++i) {
ResumeThread(cp->ProcessInformation[i].hThread);
}
/* ---- It is no longer safe to call kwsysProcessCleanup. ----- */
/* Tell the pipe threads that a process has started. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
}
/* We don't care about the children's main threads. */
for (i = 0; i < cp->NumberOfCommands; ++i) {
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
}
/* No pipe has reported data. */
cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
cp->PipesLeft = KWSYSPE_PIPE_COUNT;
/* The process has now started. */
cp->State = kwsysProcess_State_Executing;
cp->Detached = cp->OptionDetach;
}
void kwsysProcess_Disown(kwsysProcess* cp)
{
int i;
/* Make sure we are executing a detached process. */
if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
cp->TimeoutExpired || cp->Killed || cp->Terminated) {
return;
}
/* Disable the reading threads. */
kwsysProcessDisablePipeThreads(cp);
/* Wait for all pipe threads to reset. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
}
/* We will not wait for exit, so cleanup now. */
kwsysProcessCleanup(cp, 0);
/* The process has been disowned. */
cp->State = kwsysProcess_State_Disowned;
}
int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
double* userTimeout)
{
kwsysProcessTime userStartTime;
kwsysProcessTime timeoutLength;
kwsysProcessTime timeoutTime;
DWORD timeout;
int user;
int done = 0;
int expired = 0;
int pipeId = kwsysProcess_Pipe_None;
DWORD w;
/* Make sure we are executing a process. */
if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
cp->TimeoutExpired) {
return kwsysProcess_Pipe_None;
}
/* Record the time at which user timeout period starts. */
userStartTime = kwsysProcessTimeGetCurrent();
/* Calculate the time at which a timeout will expire, and whether it
is the user or process timeout. */
user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime);
/* Loop until we have a reason to return. */
while (!done && cp->PipesLeft > 0) {
/* If we previously got data from a thread, let it know we are
done with the data. */
if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
}
/* Setup a timeout if required. */
if (kwsysProcessGetTimeoutLeft(&timeoutTime, user ? userTimeout : 0,
&timeoutLength)) {
/* Timeout has already expired. */
expired = 1;
break;
}
if (timeoutTime.QuadPart < 0) {
timeout = INFINITE;
} else {
timeout = kwsysProcessTimeToDWORD(timeoutLength);
}
/* Wait for a pipe's thread to signal or a process to terminate. */
w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents, 0,
timeout);
if (w == WAIT_TIMEOUT) {
/* Timeout has expired. */
expired = 1;
done = 1;
} else if (w == WAIT_OBJECT_0) {
/* Save the index of the reporting thread and release the mutex.
The thread will block until we signal its Empty mutex. */
cp->CurrentIndex = cp->SharedIndex;
ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
/* Data are available or a pipe closed. */
if (cp->Pipe[cp->CurrentIndex].Closed) {
/* The pipe closed at the write end. Close the read end and
inform the wakeup thread it is done with this process. */
kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read);
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Waker.Go, 1, 0);
KWSYSPE_DEBUG((stderr, "wakeup %d\n", cp->CurrentIndex));
--cp->PipesLeft;
} else if (data && length) {
/* Report this data. */
*data = cp->Pipe[cp->CurrentIndex].DataBuffer;
*length = cp->Pipe[cp->CurrentIndex].DataLength;
switch (cp->CurrentIndex) {
case KWSYSPE_PIPE_STDOUT:
pipeId = kwsysProcess_Pipe_STDOUT;
break;
case KWSYSPE_PIPE_STDERR:
pipeId = kwsysProcess_Pipe_STDERR;
break;
}
done = 1;
}
} else {
/* A process has terminated. */
kwsysProcessDestroy(cp, w - WAIT_OBJECT_0);
}
}
/* Update the user timeout. */
if (userTimeout) {
kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
kwsysProcessTime difference =
kwsysProcessTimeSubtract(userEndTime, userStartTime);
double d = kwsysProcessTimeToDouble(difference);
*userTimeout -= d;
if (*userTimeout < 0) {
*userTimeout = 0;
}
}
/* Check what happened. */
if (pipeId) {
/* Data are ready on a pipe. */
return pipeId;
} else if (expired) {
/* A timeout has expired. */
if (user) {
/* The user timeout has expired. It has no time left. */
return kwsysProcess_Pipe_Timeout;
} else {
/* The process timeout has expired. Kill the child now. */
KWSYSPE_DEBUG((stderr, "killing child because timeout expired\n"));
kwsysProcess_Kill(cp);
cp->TimeoutExpired = 1;
cp->Killed = 0;
return kwsysProcess_Pipe_None;
}
} else {
/* The children have terminated and no more data are available. */
return kwsysProcess_Pipe_None;
}
}
int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
{
int i;
int pipe;
/* Make sure we are executing a process. */
if (!cp || cp->State != kwsysProcess_State_Executing) {
return 1;
}
/* Wait for the process to terminate. Ignore all data. */
while ((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) {
if (pipe == kwsysProcess_Pipe_Timeout) {
/* The user timeout has expired. */
return 0;
}
}
KWSYSPE_DEBUG((stderr, "no more data\n"));
/* When the last pipe closes in WaitForData, the loop terminates
without releasing the pipe's thread. Release it now. */
if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
}
/* Wait for all pipe threads to reset. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
KWSYSPE_DEBUG((stderr, "waiting reader reset %d\n", i));
WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
KWSYSPE_DEBUG((stderr, "waiting waker reset %d\n", i));
WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
}
/* ---- It is now safe again to call kwsysProcessCleanup. ----- */
/* Close all the pipes. */
kwsysProcessCleanup(cp, 0);
/* Determine the outcome. */
if (cp->Killed) {
/* We killed the child. */
cp->State = kwsysProcess_State_Killed;
} else if (cp->TimeoutExpired) {
/* The timeout expired. */
cp->State = kwsysProcess_State_Expired;
} else {
/* The children exited. Report the outcome of the child processes. */
for (i = 0; i < cp->NumberOfCommands; ++i) {
cp->ProcessResults[i].ExitCode = cp->CommandExitCodes[i];
if ((cp->ProcessResults[i].ExitCode & 0xF0000000) == 0xC0000000) {
/* Child terminated due to exceptional behavior. */
cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exception;
cp->ProcessResults[i].ExitValue = 1;
kwsysProcessSetExitExceptionByIndex(cp, cp->ProcessResults[i].ExitCode,
i);
} else {
/* Child exited without exception. */
cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exited;
cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None;
cp->ProcessResults[i].ExitValue = cp->ProcessResults[i].ExitCode;
}
}
/* support legacy state status value */
cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State;
}
return 1;
}
void kwsysProcess_Interrupt(kwsysProcess* cp)
{
int i;
/* Make sure we are executing a process. */
if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
cp->Killed) {
KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n"));
return;
}
/* Skip actually interrupting the child if it has already terminated. */
if (cp->Terminated) {
KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n"));
return;
}
/* Interrupt the children. */
if (cp->CreateProcessGroup) {
if (cp->ProcessInformation) {
for (i = 0; i < cp->NumberOfCommands; ++i) {
/* Make sure the process handle isn't closed (e.g. from disowning). */
if (cp->ProcessInformation[i].hProcess) {
/* The user created a process group for this process. The group ID
is the process ID for the original process in the group. Note
that we have to use Ctrl+Break: Ctrl+C is not allowed for process
groups. */
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
cp->ProcessInformation[i].dwProcessId);
}
}
}
} else {
/* No process group was created. Kill our own process group... */
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
}
}
void kwsysProcess_Kill(kwsysProcess* cp)
{
int i;
/* Make sure we are executing a process. */
if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
cp->Killed) {
KWSYSPE_DEBUG((stderr, "kill: child not executing\n"));
return;
}
/* Disable the reading threads. */
KWSYSPE_DEBUG((stderr, "kill: disabling pipe threads\n"));
kwsysProcessDisablePipeThreads(cp);
/* Skip actually killing the child if it has already terminated. */
if (cp->Terminated) {
KWSYSPE_DEBUG((stderr, "kill: child already terminated\n"));
return;
}
/* Kill the children. */
cp->Killed = 1;
for (i = 0; i < cp->NumberOfCommands; ++i) {
kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId);
/* Remove from global list of processes and close handles. */
kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
}
/* We are killing the children and ignoring all data. Do not wait
for them to exit. */
}
void kwsysProcess_KillPID(unsigned long process_id)
{
kwsysProcessKillTree((DWORD)process_id);
}
/*
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)
{
int i;
/* Reset internal status flags. */
cp->TimeoutExpired = 0;
cp->Terminated = 0;
cp->Killed = 0;
free(cp->ProcessResults);
/* Allocate process result information for each process. */
cp->ProcessResults = (kwsysProcessResults*)malloc(
sizeof(kwsysProcessResults) * (cp->NumberOfCommands));
if (!cp->ProcessResults) {
return 0;
}
ZeroMemory(cp->ProcessResults,
sizeof(kwsysProcessResults) * cp->NumberOfCommands);
for (i = 0; i < cp->NumberOfCommands; i++) {
cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None;
cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting;
cp->ProcessResults[i].ExitCode = 1;
cp->ProcessResults[i].ExitValue = 1;
strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception");
}
/* Allocate process information for each process. */
free(cp->ProcessInformation);
cp->ProcessInformation = (PROCESS_INFORMATION*)malloc(
sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
if (!cp->ProcessInformation) {
return 0;
}
ZeroMemory(cp->ProcessInformation,
sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
free(cp->CommandExitCodes);
cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD) * cp->NumberOfCommands);
if (!cp->CommandExitCodes) {
return 0;
}
ZeroMemory(cp->CommandExitCodes, sizeof(DWORD) * cp->NumberOfCommands);
/* Allocate event wait array. The first event is cp->Full, the rest
are the process termination events. */
cp->ProcessEvents =
(PHANDLE)malloc(sizeof(HANDLE) * (cp->NumberOfCommands + 1));
if (!cp->ProcessEvents) {
return 0;
}
ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands + 1));
cp->ProcessEvents[0] = cp->Full;
cp->ProcessEventsLength = cp->NumberOfCommands + 1;
/* Allocate space to save the real working directory of this process. */
if (cp->WorkingDirectory) {
cp->RealWorkingDirectoryLength = GetCurrentDirectoryW(0, 0);
if (cp->RealWorkingDirectoryLength > 0) {
cp->RealWorkingDirectory =
malloc(cp->RealWorkingDirectoryLength * sizeof(wchar_t));
if (!cp->RealWorkingDirectory) {
return 0;
}
}
}
{
for (i = 0; i < 3; ++i) {
cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
}
}
return 1;
}
static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
{
DWORD flags;
/* Check whether the handle is valid for this process. */
if (in != INVALID_HANDLE_VALUE && GetHandleInformation(in, &flags)) {
/* Use the handle as-is if it is already inherited. */
if (flags & HANDLE_FLAG_INHERIT) {
*out = in;
return ERROR_SUCCESS;
}
/* Create an inherited copy of this handle. */
if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out, 0,
TRUE, DUPLICATE_SAME_ACCESS)) {
return ERROR_SUCCESS;
} else {
return GetLastError();
}
} else {
/* The given handle is not valid for this process. Some child
processes may break if they do not have a valid standard handle,
so open NUL to give to the child. */
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa, sizeof(sa));
sa.nLength = (DWORD)sizeof(sa);
sa.bInheritHandle = 1;
*out = CreateFileW(
L"NUL",
(isStdIn ? GENERIC_READ : (GENERIC_WRITE | FILE_READ_ATTRIBUTES)),
FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0);
return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError();
}
}
DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
kwsysProcessCreateInformation* si)
{
DWORD creationFlags;
DWORD error = ERROR_SUCCESS;
/* Check if we are currently exiting. */
if (!kwsysTryEnterCreateProcessSection()) {
/* The Ctrl handler is currently working on exiting our process. Rather
than return an error code, which could cause incorrect conclusions to be
reached by the caller, we simply hang. (For example, a CMake try_run
configure step might cause the project to configure wrong.) */
Sleep(INFINITE);
}
/* Create the child in a suspended state so we can wait until all
children have been created before running any one. */
creationFlags = CREATE_SUSPENDED;
if (cp->CreateProcessGroup) {
creationFlags |= CREATE_NEW_PROCESS_GROUP;
}
/* Create inherited copies of the handles. */
(error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput,
si->hStdInput, 1)) ||
(error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput,
si->hStdOutput, 0)) ||
(error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError,
si->hStdError, 0)) ||
/* Create the process. */
(!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0, 0,
&si->StartupInfo, &cp->ProcessInformation[index]) &&
(error = GetLastError()));
/* Close the inherited copies of the handles. */
if (si->StartupInfo.hStdInput != si->hStdInput) {
kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
}
if (si->StartupInfo.hStdOutput != si->hStdOutput) {
kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
}
if (si->StartupInfo.hStdError != si->hStdError) {
kwsysProcessCleanupHandle(&si->StartupInfo.hStdError);
}
/* Add the process to the global list of processes. */
if (!error &&
!kwsysProcessesAdd(cp->ProcessInformation[index].hProcess,
cp->ProcessInformation[index].dwProcessId,
cp->CreateProcessGroup)) {
/* This failed for some reason. Kill the suspended process. */
TerminateProcess(cp->ProcessInformation[index].hProcess, 1);
/* And clean up... */
kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread);
strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed");
error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason. */
}
/* If the console Ctrl handler is waiting for us, this will release it... */
kwsysLeaveCreateProcessSection();
return error;
}
void kwsysProcessDestroy(kwsysProcess* cp, int event)
{
int i;
int index;
/* Find the process index for the termination event. */
for (index = 0; index < cp->NumberOfCommands; ++index) {
if (cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event]) {
break;
}
}
/* Check the exit code of the process. */
GetExitCodeProcess(cp->ProcessInformation[index].hProcess,
&cp->CommandExitCodes[index]);
/* Remove from global list of processes. */
kwsysProcessesRemove(cp->ProcessInformation[index].hProcess);
/* Close the process handle for the terminated process. */
kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
/* Remove the process from the available events. */
cp->ProcessEventsLength -= 1;
for (i = event; i < cp->ProcessEventsLength; ++i) {
cp->ProcessEvents[i] = cp->ProcessEvents[i + 1];
}
/* Check if all processes have terminated. */
if (cp->ProcessEventsLength == 1) {
cp->Terminated = 1;
/* Close our copies of the pipe write handles so the pipe threads
can detect end-of-data. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
/* TODO: If the child created its own child (our grandchild)
which inherited a copy of the pipe write-end then the pipe
may not close and we will still need the waker write pipe.
However we still want to be able to detect end-of-data in the
normal case. The reader thread will have to switch to using
PeekNamedPipe to read the last bit of data from the pipe
without blocking. This is equivalent to using a non-blocking
read on posix. */
KWSYSPE_DEBUG((stderr, "closing wakeup write %d\n", i));
kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
}
}
}
DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
{
HANDLE fout;
wchar_t* wname;
DWORD error;
if (!name) {
return ERROR_INVALID_PARAMETER;
}
/* Close the existing handle. */
kwsysProcessCleanupHandle(phandle);
/* Create a handle to write a file for the pipe. */
wname = kwsysEncoding_DupToWide(name);
fout =
CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
error = GetLastError();
free(wname);
if (fout == INVALID_HANDLE_VALUE) {
return error;
}
/* Assign the replacement handle. */
*phandle = fout;
return ERROR_SUCCESS;
}
void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
{
/* Close the existing handle. */
kwsysProcessCleanupHandle(handle);
/* Store the new standard handle. */
*handle = GetStdHandle(nStdHandle);
}
void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle)
{
/* Close the existing handle. */
kwsysProcessCleanupHandle(handle);
/* Store the new given handle. */
*handle = native;
}
/* Close the given handle if it is open. Reset its value to 0. */
void kwsysProcessCleanupHandle(PHANDLE h)
{
if (h && *h && *h != INVALID_HANDLE_VALUE &&
*h != GetStdHandle(STD_INPUT_HANDLE) &&
*h != GetStdHandle(STD_OUTPUT_HANDLE) &&
*h != GetStdHandle(STD_ERROR_HANDLE)) {
CloseHandle(*h);
*h = INVALID_HANDLE_VALUE;
}
}
/* Close all handles created by kwsysProcess_Execute. */
void kwsysProcessCleanup(kwsysProcess* cp, DWORD error)
{
int i;
/* If this is an error case, report the error. */
if (error) {
/* Construct an error message if one has not been provided already. */
if (cp->ErrorMessage[0] == 0) {
/* Format the error message. */
wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE];
DWORD length = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_msg,
KWSYSPE_PIPE_BUFFER_SIZE, 0);
if (length < 1) {
/* FormatMessage failed. Use a default message. */
_snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
"Process execution failed with error 0x%X. "
"FormatMessage failed with error 0x%X",
error, GetLastError());
}
if (!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage,
KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL)) {
/* WideCharToMultiByte failed. Use a default message. */
_snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
"Process execution failed with error 0x%X. "
"WideCharToMultiByte failed with error 0x%X",
error, GetLastError());
}
}
/* Remove trailing period and newline, if any. */
kwsysProcessCleanErrorMessage(cp);
/* Set the error state. */
cp->State = kwsysProcess_State_Error;
/* Cleanup any processes already started in a suspended state. */
if (cp->ProcessInformation) {
for (i = 0; i < cp->NumberOfCommands; ++i) {
if (cp->ProcessInformation[i].hProcess) {
TerminateProcess(cp->ProcessInformation[i].hProcess, 255);
WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE);
}
}
for (i = 0; i < cp->NumberOfCommands; ++i) {
/* Remove from global list of processes and close handles. */
kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
}
}
/* Restore the working directory. */
if (cp->RealWorkingDirectory) {
SetCurrentDirectoryW(cp->RealWorkingDirectory);
}
}
/* Free memory. */
if (cp->ProcessInformation) {
free(cp->ProcessInformation);
cp->ProcessInformation = 0;
}
if (cp->ProcessEvents) {
free(cp->ProcessEvents);
cp->ProcessEvents = 0;
}
if (cp->RealWorkingDirectory) {
free(cp->RealWorkingDirectory);
cp->RealWorkingDirectory = 0;
}
/* Close each pipe. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
kwsysProcessCleanupHandle(&cp->Pipe[i].Read);
cp->Pipe[i].Closed = 0;
}
for (i = 0; i < 3; ++i) {
kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
}
}
void kwsysProcessCleanErrorMessage(kwsysProcess* cp)
{
/* Remove trailing period and newline, if any. */
size_t length = strlen(cp->ErrorMessage);
if (cp->ErrorMessage[length - 1] == '\n') {
cp->ErrorMessage[length - 1] = 0;
--length;
if (length > 0 && cp->ErrorMessage[length - 1] == '\r') {
cp->ErrorMessage[length - 1] = 0;
--length;
}
}
if (length > 0 && cp->ErrorMessage[length - 1] == '.') {
cp->ErrorMessage[length - 1] = 0;
}
}
/* Get the time at which either the process or user timeout will
expire. Returns 1 if the user timeout is first, and 0 otherwise. */
int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime)
{
/* The first time this is called, we need to calculate the time at
which the child will timeout. */
if (cp->Timeout && cp->TimeoutTime.QuadPart < 0) {
kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout);
cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length);
}
/* Start with process timeout. */
*timeoutTime = cp->TimeoutTime;
/* Check if the user timeout is earlier. */
if (userTimeout) {
kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
kwsysProcessTime userTimeoutLength =
kwsysProcessTimeFromDouble(*userTimeout);
kwsysProcessTime userTimeoutTime =
kwsysProcessTimeAdd(currentTime, userTimeoutLength);
if (timeoutTime->QuadPart < 0 ||
kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) {
*timeoutTime = userTimeoutTime;
return 1;
}
}
return 0;
}
/* Get the length of time before the given timeout time arrives.
Returns 1 if the time has already arrived, and 0 otherwise. */
int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
double* userTimeout,
kwsysProcessTime* timeoutLength)
{
if (timeoutTime->QuadPart < 0) {
/* No timeout time has been requested. */
return 0;
} else {
/* Calculate the remaining time. */
kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
*timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime);
if (timeoutLength->QuadPart < 0 && userTimeout && *userTimeout <= 0) {
/* Caller has explicitly requested a zero timeout. */
timeoutLength->QuadPart = 0;
}
if (timeoutLength->QuadPart < 0) {
/* Timeout has already expired. */
return 1;
} else {
/* There is some time left. */
return 0;
}
}
}
kwsysProcessTime kwsysProcessTimeGetCurrent()
{
kwsysProcessTime current;
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
current.LowPart = ft.dwLowDateTime;
current.HighPart = ft.dwHighDateTime;
return current;
}
DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t)
{
return (DWORD)(t.QuadPart * 0.0001);
}
double kwsysProcessTimeToDouble(kwsysProcessTime t)
{
return t.QuadPart * 0.0000001;
}
kwsysProcessTime kwsysProcessTimeFromDouble(double d)
{
kwsysProcessTime t;
t.QuadPart = (LONGLONG)(d * 10000000);
return t;
}
int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2)
{
return in1.QuadPart < in2.QuadPart;
}
kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
kwsysProcessTime in2)
{
kwsysProcessTime out;
out.QuadPart = in1.QuadPart + in2.QuadPart;
return out;
}
kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
kwsysProcessTime in2)
{
kwsysProcessTime out;
out.QuadPart = in1.QuadPart - in2.QuadPart;
return out;
}
#define KWSYSPE_CASE(type, str) \
cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \
strcpy(cp->ProcessResults[idx].ExitExceptionString, str)
static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code,
int idx)
{
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->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other;
_snprintf(cp->ProcessResults[idx].ExitExceptionString,
KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code);
break;
}
}
#undef KWSYSPE_CASE
typedef struct kwsysProcess_List_s kwsysProcess_List;
static kwsysProcess_List* kwsysProcess_List_New(void);
static void kwsysProcess_List_Delete(kwsysProcess_List* self);
static int kwsysProcess_List_Update(kwsysProcess_List* self);
static int kwsysProcess_List_NextProcess(kwsysProcess_List* self);
static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self);
static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self);
/* Windows NT 4 API definitions. */
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
typedef LONG NTSTATUS;
typedef LONG KPRIORITY;
typedef struct _UNICODE_STRING UNICODE_STRING;
struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
};
/* The process information structure. Declare only enough to get
process identifiers. The rest may be ignored because we use the
NextEntryDelta to move through an array of instances. */
typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION;
typedef SYSTEM_PROCESS_INFORMATION* PSYSTEM_PROCESS_INFORMATION;
struct _SYSTEM_PROCESS_INFORMATION
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved1[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
};
/* Toolhelp32 API definitions. */
#define TH32CS_SNAPPROCESS 0x00000002
#if defined(_WIN64)
typedef unsigned __int64 ProcessULONG_PTR;
#else
typedef unsigned long ProcessULONG_PTR;
#endif
typedef struct tagPROCESSENTRY32 PROCESSENTRY32;
typedef PROCESSENTRY32* LPPROCESSENTRY32;
struct tagPROCESSENTRY32
{
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ProcessULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
char szExeFile[MAX_PATH];
};
/* Windows API function types. */
typedef HANDLE(WINAPI* CreateToolhelp32SnapshotType)(DWORD, DWORD);
typedef BOOL(WINAPI* Process32FirstType)(HANDLE, LPPROCESSENTRY32);
typedef BOOL(WINAPI* Process32NextType)(HANDLE, LPPROCESSENTRY32);
typedef NTSTATUS(WINAPI* ZwQuerySystemInformationType)(ULONG, PVOID, ULONG,
PULONG);
static int kwsysProcess_List__New_NT4(kwsysProcess_List* self);
static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self);
static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self);
static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self);
static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self);
static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self);
static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self);
static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self);
static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self);
static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self);
static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self);
static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self);
struct kwsysProcess_List_s
{
/* Implementation switches at runtime based on version of Windows. */
int NT4;
/* Implementation functions and data for NT 4. */
ZwQuerySystemInformationType P_ZwQuerySystemInformation;
char* Buffer;
int BufferSize;
PSYSTEM_PROCESS_INFORMATION CurrentInfo;
/* Implementation functions and data for other Windows versions. */
CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot;
Process32FirstType P_Process32First;
Process32NextType P_Process32Next;
HANDLE Snapshot;
PROCESSENTRY32 CurrentEntry;
};
static kwsysProcess_List* kwsysProcess_List_New(void)
{
OSVERSIONINFO osv;
kwsysProcess_List* self;
/* Allocate and initialize the list object. */
if (!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List)))) {
return 0;
}
memset(self, 0, sizeof(*self));
/* Select an implementation. */
ZeroMemory(&osv, sizeof(osv));
osv.dwOSVersionInfoSize = sizeof(osv);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
# elif defined __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
#endif
GetVersionEx(&osv);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# ifdef __clang__
# pragma clang diagnostic pop
# else
# pragma warning(pop)
# endif
#endif
self->NT4 =
(osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1
: 0;
/* Initialize the selected implementation. */
if (!(self->NT4 ? kwsysProcess_List__New_NT4(self)
: kwsysProcess_List__New_Snapshot(self))) {
kwsysProcess_List_Delete(self);
return 0;
}
/* Update to the current set of processes. */
if (!kwsysProcess_List_Update(self)) {
kwsysProcess_List_Delete(self);
return 0;
}
return self;
}
static void kwsysProcess_List_Delete(kwsysProcess_List* self)
{
if (self) {
if (self->NT4) {
kwsysProcess_List__Delete_NT4(self);
} else {
kwsysProcess_List__Delete_Snapshot(self);
}
free(self);
}
}
static int kwsysProcess_List_Update(kwsysProcess_List* self)
{
return self ? (self->NT4 ? kwsysProcess_List__Update_NT4(self)
: kwsysProcess_List__Update_Snapshot(self))
: 0;
}
static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self)
{
return self ? (self->NT4 ? kwsysProcess_List__GetProcessId_NT4(self)
: kwsysProcess_List__GetProcessId_Snapshot(self))
: -1;
}
static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self)
{
return self ? (self->NT4 ? kwsysProcess_List__GetParentId_NT4(self)
: kwsysProcess_List__GetParentId_Snapshot(self))
: -1;
}
static int kwsysProcess_List_NextProcess(kwsysProcess_List* self)
{
return (self ? (self->NT4 ? kwsysProcess_List__Next_NT4(self)
: kwsysProcess_List__Next_Snapshot(self))
: 0);
}
static int kwsysProcess_List__New_NT4(kwsysProcess_List* self)
{
/* Get a handle to the NT runtime module that should already be
loaded in this program. This does not actually increment the
reference count to the module so we do not need to close the
handle. */
HMODULE hNT = GetModuleHandleW(L"ntdll.dll");
if (hNT) {
/* Get pointers to the needed API functions. */
self->P_ZwQuerySystemInformation =
((ZwQuerySystemInformationType)GetProcAddress(
hNT, "ZwQuerySystemInformation"));
}
if (!self->P_ZwQuerySystemInformation) {
return 0;
}
/* Allocate an initial process information buffer. */
self->BufferSize = 32768;
self->Buffer = (char*)malloc(self->BufferSize);
return self->Buffer ? 1 : 0;
}
static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self)
{
/* Free the process information buffer. */
free(self->Buffer);
}
static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self)
{
self->CurrentInfo = 0;
for (;;) {
/* Query number 5 is for system process list. */
NTSTATUS status =
self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0);
if (status == STATUS_INFO_LENGTH_MISMATCH) {
/* The query requires a bigger buffer. */
int newBufferSize = self->BufferSize * 2;
char* newBuffer = (char*)malloc(newBufferSize);
if (newBuffer) {
free(self->Buffer);
self->Buffer = newBuffer;
self->BufferSize = newBufferSize;
} else {
return 0;
}
} else if (status >= 0) {
/* The query succeeded. Initialize traversal of the process list. */
self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer;
return 1;
} else {
/* The query failed. */
return 0;
}
}
}
static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self)
{
if (self->CurrentInfo) {
if (self->CurrentInfo->NextEntryDelta > 0) {
self->CurrentInfo =
((PSYSTEM_PROCESS_INFORMATION)((char*)self->CurrentInfo +
self->CurrentInfo->NextEntryDelta));
return 1;
}
self->CurrentInfo = 0;
}
return 0;
}
static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self)
{
return self->CurrentInfo ? self->CurrentInfo->ProcessId : -1;
}
static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self)
{
return self->CurrentInfo ? self->CurrentInfo->InheritedFromProcessId : -1;
}
static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self)
{
/* Get a handle to the Windows runtime module that should already be
loaded in this program. This does not actually increment the
reference count to the module so we do not need to close the
handle. */
HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
if (hKernel) {
self->P_CreateToolhelp32Snapshot =
((CreateToolhelp32SnapshotType)GetProcAddress(
hKernel, "CreateToolhelp32Snapshot"));
self->P_Process32First =
((Process32FirstType)GetProcAddress(hKernel, "Process32First"));
self->P_Process32Next =
((Process32NextType)GetProcAddress(hKernel, "Process32Next"));
}
return (self->P_CreateToolhelp32Snapshot && self->P_Process32First &&
self->P_Process32Next)
? 1
: 0;
}
static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self)
{
if (self->Snapshot) {
CloseHandle(self->Snapshot);
}
}
static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self)
{
if (self->Snapshot) {
CloseHandle(self->Snapshot);
}
if (!(self->Snapshot =
self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) {
return 0;
}
ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry));
self->CurrentEntry.dwSize = sizeof(self->CurrentEntry);
if (!self->P_Process32First(self->Snapshot, &self->CurrentEntry)) {
CloseHandle(self->Snapshot);
self->Snapshot = 0;
return 0;
}
return 1;
}
static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self)
{
if (self->Snapshot) {
if (self->P_Process32Next(self->Snapshot, &self->CurrentEntry)) {
return 1;
}
CloseHandle(self->Snapshot);
self->Snapshot = 0;
}
return 0;
}
static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self)
{
return self->Snapshot ? self->CurrentEntry.th32ProcessID : -1;
}
static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self)
{
return self->Snapshot ? self->CurrentEntry.th32ParentProcessID : -1;
}
static void kwsysProcessKill(DWORD pid)
{
HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid);
if (h) {
TerminateProcess(h, 255);
WaitForSingleObject(h, INFINITE);
CloseHandle(h);
}
}
static void kwsysProcessKillTree(int pid)
{
kwsysProcess_List* plist = kwsysProcess_List_New();
kwsysProcessKill(pid);
if (plist) {
do {
if (kwsysProcess_List_GetCurrentParentId(plist) == pid) {
int ppid = kwsysProcess_List_GetCurrentProcessId(plist);
kwsysProcessKillTree(ppid);
}
} while (kwsysProcess_List_NextProcess(plist));
kwsysProcess_List_Delete(plist);
}
}
static void kwsysProcessDisablePipeThreads(kwsysProcess* cp)
{
int i;
/* If data were just reported data, release the pipe's thread. */
if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
}
/* Wakeup all reading threads that are not on closed pipes. */
for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
/* The wakeup threads will write one byte to the pipe write ends.
If there are no data in the pipe then this is enough to wakeup
the reading threads. If there are already data in the pipe
this may block. We cannot use PeekNamedPipe to check whether
there are data because an outside process might still be
writing data if we are disowning it. Also, PeekNamedPipe will
block if checking a pipe on which the reading thread is
currently calling ReadPipe. Therefore we need a separate
thread to call WriteFile. If it blocks, that is okay because
it will unblock when we close the read end and break the pipe
below. */
if (cp->Pipe[i].Read) {
KWSYSPE_DEBUG((stderr, "releasing waker %d\n", i));
ReleaseSemaphore(cp->Pipe[i].Waker.Go, 1, 0);
}
}
/* Tell pipe threads to reset until we run another process. */
while (cp->PipesLeft > 0) {
/* The waking threads will cause all reading threads to report.
Wait for the next one and save its index. */
KWSYSPE_DEBUG((stderr, "waiting for reader\n"));
WaitForSingleObject(cp->Full, INFINITE);
cp->CurrentIndex = cp->SharedIndex;
ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
KWSYSPE_DEBUG((stderr, "got reader %d\n", cp->CurrentIndex));
/* We are done reading this pipe. Close its read handle. */
cp->Pipe[cp->CurrentIndex].Closed = 1;
kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read);
--cp->PipesLeft;
/* Tell the reading thread we are done with the data. It will
reset immediately because the pipe is closed. */
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
}
}
/* Global set of executing processes for use by the Ctrl handler.
This global instance will be zero-initialized by the compiler.
Note that the console Ctrl handler runs on a background thread and so
everything it does must be thread safe. Here, we track the hProcess
HANDLEs directly instead of kwsysProcess instances, so that we don't have
to make kwsysProcess thread safe. */
typedef struct kwsysProcessInstance_s
{
HANDLE hProcess;
DWORD dwProcessId;
int NewProcessGroup; /* Whether the process was created in a new group. */
} kwsysProcessInstance;
typedef struct kwsysProcessInstances_s
{
/* Whether we have initialized key fields below, like critical sections. */
int Initialized;
/* Ctrl handler runs on a different thread, so we must sync access. */
CRITICAL_SECTION Lock;
int Exiting;
size_t Count;
size_t Size;
kwsysProcessInstance* Processes;
} kwsysProcessInstances;
static kwsysProcessInstances kwsysProcesses;
/* Initialize critial section and set up console Ctrl handler. You MUST call
this before using any other kwsysProcesses* functions below. */
static int kwsysProcessesInitialize(void)
{
/* Initialize everything if not done already. */
if (!kwsysProcesses.Initialized) {
InitializeCriticalSection(&kwsysProcesses.Lock);
/* Set up console ctrl handler. */
if (!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE)) {
return 0;
}
kwsysProcesses.Initialized = 1;
}
return 1;
}
/* The Ctrl handler waits on the global list of processes. To prevent an
orphaned process, do not create a new process if the Ctrl handler is
already running. Do so by using this function to check if it is ok to
create a process. */
static int kwsysTryEnterCreateProcessSection(void)
{
/* Enter main critical section; this means creating a process and the Ctrl
handler are mutually exclusive. */
EnterCriticalSection(&kwsysProcesses.Lock);
/* Indicate to the caller if they can create a process. */
if (kwsysProcesses.Exiting) {
LeaveCriticalSection(&kwsysProcesses.Lock);
return 0;
} else {
return 1;
}
}
/* Matching function on successful kwsysTryEnterCreateProcessSection return.
Make sure you called kwsysProcessesAdd if applicable before calling this.*/
static void kwsysLeaveCreateProcessSection(void)
{
LeaveCriticalSection(&kwsysProcesses.Lock);
}
/* Add new process to global process list. The Ctrl handler will wait for
the process to exit before it returns. Do not close the process handle
until after calling kwsysProcessesRemove. The newProcessGroup parameter
must be set if the process was created with CREATE_NEW_PROCESS_GROUP. */
static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid,
int newProcessGroup)
{
if (!kwsysProcessesInitialize() || !hProcess ||
hProcess == INVALID_HANDLE_VALUE) {
return 0;
}
/* Enter the critical section. */
EnterCriticalSection(&kwsysProcesses.Lock);
/* Make sure there is enough space for the new process handle. */
if (kwsysProcesses.Count == kwsysProcesses.Size) {
size_t newSize;
kwsysProcessInstance* newArray;
/* Start with enough space for a small number of process handles
and double the size each time more is needed. */
newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4;
/* Try allocating the new block of memory. */
if ((newArray = (kwsysProcessInstance*)malloc(
newSize * sizeof(kwsysProcessInstance)))) {
/* Copy the old process handles to the new memory. */
if (kwsysProcesses.Count > 0) {
memcpy(newArray, kwsysProcesses.Processes,
kwsysProcesses.Count * sizeof(kwsysProcessInstance));
}
} else {
/* Failed to allocate memory for the new process handle set. */
LeaveCriticalSection(&kwsysProcesses.Lock);
return 0;
}
/* Free original array. */
free(kwsysProcesses.Processes);
/* Update original structure with new allocation. */
kwsysProcesses.Size = newSize;
kwsysProcesses.Processes = newArray;
}
/* Append the new process information to the set. */
kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess;
kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid;
kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup =
newProcessGroup;
/* Leave critical section and return success. */
LeaveCriticalSection(&kwsysProcesses.Lock);
return 1;
}
/* Removes process to global process list. */
static void kwsysProcessesRemove(HANDLE hProcess)
{
size_t i;
if (!hProcess || hProcess == INVALID_HANDLE_VALUE) {
return;
}
EnterCriticalSection(&kwsysProcesses.Lock);
/* Find the given process in the set. */
for (i = 0; i < kwsysProcesses.Count; ++i) {
if (kwsysProcesses.Processes[i].hProcess == hProcess) {
break;
}
}
if (i < kwsysProcesses.Count) {
/* Found it! Remove the process from the set. */
--kwsysProcesses.Count;
for (; i < kwsysProcesses.Count; ++i) {
kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i + 1];
}
/* If this was the last process, free the array. */
if (kwsysProcesses.Count == 0) {
kwsysProcesses.Size = 0;
free(kwsysProcesses.Processes);
kwsysProcesses.Processes = 0;
}
}
LeaveCriticalSection(&kwsysProcesses.Lock);
}
static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType)
{
size_t i;
(void)dwCtrlType;
/* Enter critical section. */
EnterCriticalSection(&kwsysProcesses.Lock);
/* Set flag indicating that we are exiting. */
kwsysProcesses.Exiting = 1;
/* If some of our processes were created in a new process group, we must
manually interrupt them. They won't otherwise receive a Ctrl+C/Break. */
for (i = 0; i < kwsysProcesses.Count; ++i) {
if (kwsysProcesses.Processes[i].NewProcessGroup) {
DWORD groupId = kwsysProcesses.Processes[i].dwProcessId;
if (groupId) {
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId);
}
}
}
/* Wait for each child process to exit. This is the key step that prevents
us from leaving several orphaned children processes running in the
background when the user presses Ctrl+C. */
for (i = 0; i < kwsysProcesses.Count; ++i) {
WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE);
}
/* Leave critical section. */
LeaveCriticalSection(&kwsysProcesses.Lock);
/* Continue on to default Ctrl handler (which calls ExitProcess). */
return FALSE;
}
void kwsysProcess_ResetStartTime(kwsysProcess* cp)
{
if (!cp) {
return;
}
/* Reset start time. */
cp->StartTime = kwsysProcessTimeGetCurrent();
}
-37
View File
@@ -1,37 +0,0 @@
KWSys
*****
Introduction
============
KWSys is the Kitware System Library. It provides platform-independent
APIs to many common system features that are implemented differently on
every platform. This library is intended to be shared among many
projects at the source level, so it has a configurable namespace.
Each project should configure KWSys to use a namespace unique to itself.
See comments in `CMakeLists.txt`_ for details.
.. _`CMakeLists.txt`: CMakeLists.txt
License
=======
KWSys is distributed under the OSI-approved BSD 3-clause License.
See `Copyright.txt`_ for details.
.. _`Copyright.txt`: Copyright.txt
Reporting Bugs
==============
KWSys has no independent issue tracker. After encountering an issue
(bug) please submit a patch using the instructions for `Contributing`_.
Otherwise please report the issue to the tracker for the project that
hosts the copy of KWSys in which the problem was found.
Contributing
============
See `CONTRIBUTING.rst`_ for instructions to contribute.
.. _`CONTRIBUTING.rst`: CONTRIBUTING.rst
-1218
View File
@@ -1,1218 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
//
// Created: MNF 06/13/89 Initial Design and Implementation
// Updated: LGO 08/09/89 Inherit from Generic
// Updated: MBN 09/07/89 Added conditional exception handling
// Updated: MBN 12/15/89 Sprinkled "const" qualifiers all over the place!
// Updated: DLS 03/22/91 New lite version
//
#include "kwsysPrivate.h"
#include KWSYS_HEADER(RegularExpression.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "RegularExpression.hxx.in"
#endif
#include <stdio.h>
#include <string.h>
namespace KWSYS_NAMESPACE {
// RegularExpression -- Copies the given regular expression.
RegularExpression::RegularExpression(const RegularExpression& rxp)
{
if (!rxp.program) {
this->program = nullptr;
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 expression
this->program[ind] = rxp.program[ind];
// Copy pointers into last successful "find" operation
this->regmatch = rxp.regmatch;
this->regmust = rxp.regmust; // Copy field
if (rxp.regmust != nullptr) {
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 = nullptr;
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 expression
this->program[ind] = rxp.program[ind];
// Copy pointers into last successful "find" operation
this->regmatch = rxp.regmatch;
this->regmust = rxp.regmust; // Copy field
if (rxp.regmust != nullptr) {
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
// Else if same start/end ptrs, return true
return (this->regmatch.start() == rxp.regmatch.start() &&
this->regmatch.end() == rxp.regmatch.end());
}
// 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
* nullptr regmlen length of regmust string
*
* Regstart and reganch permit very fast decisions on suitable starting points
* for a match, cutting down the work a lot. Regmust permits fast rejection
* of lines that cannot possibly match. The regmust tests are costly enough
* that compile() supplies a regmust only if the r.e. contains something
* potentially expensive (at present, the only such thing detected is * or +
* at the start of the r.e., which can involve a lot of backup). Regmlen is
* supplied because the test in find() needs it and compile() is computing
* it anyway.
*/
/*
* Structure for regexp "program". This is essentially a linear encoding
* of a nondeterministic finite-state machine (aka syntax charts or
* "railroad normal form" in parsing technology). Each node is an opcode
* plus a "next" pointer, possibly plus an operand. "Next" pointers of
* all nodes except BRANCH implement concatenation; a "next" pointer with
* a BRANCH on both ends of it is connecting two alternatives. (Here we
* have one of the subtle syntax dependencies: an individual BRANCH (as
* opposed to a collection of them) is never concatenated with anything
* because of operator precedence.) The operand of some types of node is
* a literal string; for others, it is a node leading into a sub-FSM. In
* particular, the operand of a BRANCH node is the first node of the branch.
* (NB this is *not* a tree structure: the tail of the branch connects
* to the thing following the set of BRANCHes.) The opcodes are:
*/
// definition number opnd? meaning
#define END 0 // no End of program.
#define BOL 1 // no Match "" at beginning of line.
#define EOL 2 // no Match "" at end of line.
#define ANY 3 // no Match any one character.
#define ANYOF 4 // str Match any character in this string.
#define ANYBUT \
5 // str Match any character not in this
// string.
#define BRANCH \
6 // node Match this alternative, or the
// next...
#define BACK 7 // no Match "", "next" ptr points backward.
#define EXACTLY 8 // str Match this string.
#define NOTHING 9 // no Match empty string.
#define STAR \
10 // node Match this (simple) thing 0 or more
// times.
#define PLUS \
11 // node Match this (simple) thing 1 or more
// times.
#define OPEN \
20 // no Mark this point in input as start of
// #n.
// OPEN+1 is number 1, etc.
#define CLOSE 30 // no Analogous to OPEN.
/*
* Opcode notes:
*
* BRANCH The set of branches constituting a single choice are hooked
* together with their "next" pointers, since precedence prevents
* anything being concatenated to any individual branch. The
* "next" pointer of the last BRANCH in a choice points to the
* thing following the whole choice. This is also where the
* final "next" pointer of each individual branch points; each
* branch starts with the operand node of a BRANCH node.
*
* BACK Normal "next" pointers all implicitly point forward; BACK
* exists to make loop structures possible.
*
* STAR,PLUS '?', and complex '*' and '+', are implemented as circular
* BRANCH structures using BACK. Simple cases (one character
* per match) are implemented with STAR and PLUS for speed
* and to minimize recursive plunges.
*
* OPEN,CLOSE ...are numbered at compile time.
*/
/*
* A node is one char of opcode followed by two chars of "next" pointer.
* "Next" pointers are stored as two 8-bit pieces, high order first. The
* value is a positive offset from the opcode of the node containing it.
* An operand, if any, simply follows the node. (Note that much of the
* code generation knows about this implicit relationship.)
*
* Using two bytes for the "next" pointer is vast overkill for most things,
* but allows patterns to get big without disasters.
*/
#define OP(p) (*(p))
#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377))
#define OPERAND(p) ((p) + 3)
const unsigned char MAGIC = 0234;
/*
* Utility definitions.
*/
#define UCHARAT(p) (reinterpret_cast<const unsigned char*>(p))[0]
#define 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
//
/////////////////////////////////////////////////////////////////////////
/*
* Read only utility variables.
*/
static char regdummy;
static char* const regdummyptr = &regdummy;
/*
* Utility class for RegularExpression::compile().
*/
class RegExpCompile
{
public:
const char* regparse; // Input-scan pointer.
int regnpar; // () count.
char* regcode; // Code-emit pointer; regdummyptr = don't.
long regsize; // Code size.
char* reg(int, int*);
char* regbranch(int*);
char* regpiece(int*);
char* regatom(int*);
char* regnode(char);
void regc(char);
void reginsert(char, char*);
static void regtail(char*, const char*);
static void regoptail(char*, const char*);
};
static const char* regnext(const char*);
static char* regnext(char*);
#ifdef STRCSPN
static int strcspn();
#endif
/*
* We can't allocate space until we know how big the compiled form will be,
* but we can't compile it (and thus know how big it is) until we've got a
* place to put the code. So we cheat: we compile it twice, once with code
* generation turned off and size counting turned on, and once "for real".
* This also means that we don't allocate space until we are sure that the
* thing really will compile successfully, and we never have to move the
* code and thus invalidate pointers into it. (Note that it has to be in
* one piece because free() must be able to free it all.)
*
* Beware that the optimization-preparation code in here knows about some
* of the structure of the compiled regexp.
*/
// compile -- compile a regular expression into internal code
// for later pattern matching.
bool RegularExpression::compile(const char* exp)
{
const char* scan;
const char* longest;
int flags;
if (exp == nullptr) {
// RAISE Error, SYM(RegularExpression), SYM(No_Expr),
printf("RegularExpression::compile(): No expression supplied.\n");
return false;
}
// First pass: determine size, legality.
RegExpCompile comp;
comp.regparse = exp;
comp.regnpar = 1;
comp.regsize = 0L;
comp.regcode = regdummyptr;
comp.regc(static_cast<char>(MAGIC));
if (!comp.reg(0, &flags)) {
printf("RegularExpression::compile(): Error in compile.\n");
return false;
}
this->regmatch.clear();
// Small enough for pointer-storage convention?
if (comp.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 != nullptr)
delete[] this->program;
//#endif
this->program = new char[comp.regsize];
this->progsize = static_cast<int>(comp.regsize);
if (this->program == nullptr) {
// RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory),
printf("RegularExpression::compile(): Out of memory.\n");
return false;
}
// Second pass: emit code.
comp.regparse = exp;
comp.regnpar = 1;
comp.regcode = this->program;
comp.regc(static_cast<char>(MAGIC));
comp.reg(0, &flags);
// Dig out information for optimizations.
this->regstart = '\0'; // Worst-case defaults.
this->reganch = 0;
this->regmust = nullptr;
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 = nullptr;
size_t len = 0;
for (; scan != nullptr; 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.
*/
char* RegExpCompile::reg(int paren, int* flagp)
{
char* ret;
char* br;
char* ender;
int parno = 0;
int flags;
*flagp = HASWIDTH; // Tentatively.
// Make an OPEN node, if parenthesized.
if (paren) {
if (regnpar >= RegularExpressionMatch::NSUBEXP) {
// RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens),
printf("RegularExpression::compile(): Too many parentheses.\n");
return nullptr;
}
parno = regnpar;
regnpar++;
ret = regnode(static_cast<char>(OPEN + parno));
} else
ret = nullptr;
// Pick up the branches, linking them together.
br = regbranch(&flags);
if (br == nullptr)
return (nullptr);
if (ret != nullptr)
regtail(ret, br); // OPEN -> first.
else
ret = br;
if (!(flags & HASWIDTH))
*flagp &= ~HASWIDTH;
*flagp |= flags & SPSTART;
while (*regparse == '|') {
regparse++;
br = regbranch(&flags);
if (br == nullptr)
return (nullptr);
regtail(ret, br); // BRANCH -> BRANCH.
if (!(flags & HASWIDTH))
*flagp &= ~HASWIDTH;
*flagp |= flags & SPSTART;
}
// Make a closing node, and hook it on the end.
ender = regnode(static_cast<char>((paren) ? CLOSE + parno : END));
regtail(ret, ender);
// Hook the tails of the branches to the closing node.
for (br = ret; br != nullptr; 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 nullptr;
} else if (!paren && *regparse != '\0') {
if (*regparse == ')') {
// RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
printf("RegularExpression::compile(): Unmatched parentheses.\n");
return nullptr;
} else {
// RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
printf("RegularExpression::compile(): Internal error.\n");
return nullptr;
}
// NOTREACHED
}
return (ret);
}
/*
- regbranch - one alternative of an | operator
*
* Implements the concatenation operator.
*/
char* RegExpCompile::regbranch(int* flagp)
{
char* ret;
char* chain;
char* latest;
int flags;
*flagp = WORST; // Tentatively.
ret = regnode(BRANCH);
chain = nullptr;
while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
latest = regpiece(&flags);
if (latest == nullptr)
return (nullptr);
*flagp |= flags & HASWIDTH;
if (chain == nullptr) // First piece.
*flagp |= flags & SPSTART;
else
regtail(chain, latest);
chain = latest;
}
if (chain == nullptr) // 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.
*/
char* RegExpCompile::regpiece(int* flagp)
{
char* ret;
char op;
char* next;
int flags;
ret = regatom(&flags);
if (ret == nullptr)
return (nullptr);
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 nullptr;
}
*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 nullptr;
}
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.
*/
char* RegExpCompile::regatom(int* flagp)
{
char* ret;
int flags;
*flagp = WORST; // Tentatively.
switch (*regparse++) {
case '^':
ret = regnode(BOL);
break;
case '$':
ret = regnode(EOL);
break;
case '.':
ret = regnode(ANY);
*flagp |= HASWIDTH | SIMPLE;
break;
case '[': {
int rxpclass;
int rxpclassend;
if (*regparse == '^') { // Complement of range.
ret = regnode(ANYBUT);
regparse++;
} else
ret = regnode(ANYOF);
if (*regparse == ']' || *regparse == '-')
regc(*regparse++);
while (*regparse != '\0' && *regparse != ']') {
if (*regparse == '-') {
regparse++;
if (*regparse == ']' || *regparse == '\0')
regc('-');
else {
rxpclass = UCHARAT(regparse - 2) + 1;
rxpclassend = UCHARAT(regparse);
if (rxpclass > rxpclassend + 1) {
// RAISE Error, SYM(RegularExpression), SYM(Invalid_Range),
printf("RegularExpression::compile(): Invalid range in [].\n");
return nullptr;
}
for (; rxpclass <= rxpclassend; rxpclass++)
regc(static_cast<char>(rxpclass));
regparse++;
}
} else
regc(*regparse++);
}
regc('\0');
if (*regparse != ']') {
// RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket),
printf("RegularExpression::compile(): Unmatched [].\n");
return nullptr;
}
regparse++;
*flagp |= HASWIDTH | SIMPLE;
} break;
case '(':
ret = reg(1, &flags);
if (ret == nullptr)
return (nullptr);
*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 nullptr;
case '?':
case '+':
case '*':
// RAISE Error, SYM(RegularExpression), SYM(No_Operand),
printf("RegularExpression::compile(): ?+* follows nothing.\n");
return nullptr;
case '\\':
if (*regparse == '\0') {
// RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash),
printf("RegularExpression::compile(): Trailing backslash.\n");
return nullptr;
}
ret = regnode(EXACTLY);
regc(*regparse++);
regc('\0');
*flagp |= HASWIDTH | SIMPLE;
break;
default: {
int len;
char ender;
regparse--;
len = int(strcspn(regparse, META));
if (len <= 0) {
// RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
printf("RegularExpression::compile(): Internal error.\n");
return nullptr;
}
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.
*/
char* RegExpCompile::regnode(char op)
{
char* ret;
char* ptr;
ret = regcode;
if (ret == regdummyptr) {
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
*/
void RegExpCompile::regc(char b)
{
if (regcode != regdummyptr)
*regcode++ = b;
else
regsize++;
}
/*
- reginsert - insert an operator in front of already-emitted operand
*
* Means relocating the operand.
*/
void RegExpCompile::reginsert(char op, char* opnd)
{
char* src;
char* dst;
char* place;
if (regcode == regdummyptr) {
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
*/
void RegExpCompile::regtail(char* p, const char* val)
{
char* scan;
char* temp;
int offset;
if (p == regdummyptr)
return;
// Find last node.
scan = p;
for (;;) {
temp = regnext(scan);
if (temp == nullptr)
break;
scan = temp;
}
if (OP(scan) == BACK)
offset = int(scan - val);
else
offset = int(val - scan);
*(scan + 1) = static_cast<char>((offset >> 8) & 0377);
*(scan + 2) = static_cast<char>(offset & 0377);
}
/*
- regoptail - regtail on operand of first argument; nop if operandless
*/
void RegExpCompile::regoptail(char* p, const char* val)
{
// "Operandless" and "op != BRANCH" are synonymous in practice.
if (p == nullptr || p == regdummyptr || OP(p) != BRANCH)
return;
regtail(OPERAND(p), val);
}
////////////////////////////////////////////////////////////////////////
//
// find and friends
//
////////////////////////////////////////////////////////////////////////
/*
* Utility class for RegularExpression::find().
*/
class RegExpFind
{
public:
const char* reginput; // String-input pointer.
const char* regbol; // Beginning of input, for ^ check.
const char** regstartp; // Pointer to startp array.
const char** regendp; // Ditto for endp.
int regtry(const char*, const char**, const char**, const char*);
int regmatch(const char*);
int regrepeat(const char*);
};
// find -- Matches the regular expression to the given string.
// Returns true if found, and sets start and end indexes accordingly.
bool RegularExpression::find(char const* string,
RegularExpressionMatch& rmatch) const
{
const char* s;
rmatch.clear();
rmatch.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 false;
}
// If there is a "must appear" string, look for it.
if (this->regmust != nullptr) {
s = string;
while ((s = strchr(s, this->regmust[0])) != nullptr) {
if (strncmp(s, this->regmust, this->regmlen) == 0)
break; // Found it.
s++;
}
if (s == nullptr) // Not present.
return false;
}
RegExpFind regFind;
// Mark beginning of line for ^ .
regFind.regbol = string;
// Simplest case: anchored match need be tried only once.
if (this->reganch)
return (
regFind.regtry(string, rmatch.startp, rmatch.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)) != nullptr) {
if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program))
return true;
s++;
}
else
// We don't -- general case.
do {
if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program))
return true;
} while (*s++ != '\0');
// Failure.
return false;
}
/*
- regtry - try match at specific point
0 failure, 1 success
*/
int RegExpFind::regtry(const char* string, const char** start,
const char** end, const char* prog)
{
int i;
const char** sp1;
const char** ep;
reginput = string;
regstartp = start;
regendp = end;
sp1 = start;
ep = end;
for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) {
*sp1++ = nullptr;
*ep++ = nullptr;
}
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
*/
int RegExpFind::regmatch(const char* prog)
{
const char* scan; // Current node.
const char* next; // Next node.
scan = prog;
while (scan != nullptr) {
next = regnext(scan);
switch (OP(scan)) {
case BOL:
if (reginput != regbol)
return (0);
break;
case EOL:
if (*reginput != '\0')
return (0);
break;
case ANY:
if (*reginput == '\0')
return (0);
reginput++;
break;
case EXACTLY: {
size_t len;
const char* opnd;
opnd = OPERAND(scan);
// Inline the first character, for speed.
if (*opnd != *reginput)
return (0);
len = strlen(opnd);
if (len > 1 && strncmp(opnd, reginput, len) != 0)
return (0);
reginput += len;
} break;
case ANYOF:
if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == nullptr)
return (0);
reginput++;
break;
case ANYBUT:
if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != nullptr)
return (0);
reginput++;
break;
case NOTHING:
break;
case BACK:
break;
case OPEN + 1:
case OPEN + 2:
case OPEN + 3:
case OPEN + 4:
case OPEN + 5:
case OPEN + 6:
case OPEN + 7:
case OPEN + 8:
case OPEN + 9: {
int no;
const char* save;
no = OP(scan) - OPEN;
save = reginput;
if (regmatch(next)) {
//
// Don't set startp if some later invocation of the
// same parentheses already has.
//
if (regstartp[no] == nullptr)
regstartp[no] = save;
return (1);
} else
return (0);
}
// break;
case CLOSE + 1:
case CLOSE + 2:
case CLOSE + 3:
case CLOSE + 4:
case CLOSE + 5:
case CLOSE + 6:
case CLOSE + 7:
case CLOSE + 8:
case CLOSE + 9: {
int no;
const char* save;
no = OP(scan) - CLOSE;
save = reginput;
if (regmatch(next)) {
//
// Don't set endp if some later invocation of the
// same parentheses already has.
//
if (regendp[no] == nullptr)
regendp[no] = save;
return (1);
} else
return (0);
}
// break;
case BRANCH: {
const char* save;
if (OP(next) != BRANCH) // No choice.
next = OPERAND(scan); // Avoid recursion.
else {
do {
save = reginput;
if (regmatch(OPERAND(scan)))
return (1);
reginput = save;
scan = regnext(scan);
} while (scan != nullptr && OP(scan) == BRANCH);
return (0);
// NOTREACHED
}
} break;
case STAR:
case PLUS: {
char nextch;
int no;
const char* save;
int min_no;
//
// Lookahead to avoid useless match attempts when we know
// what character comes next.
//
nextch = '\0';
if (OP(next) == EXACTLY)
nextch = *OPERAND(next);
min_no = (OP(scan) == STAR) ? 0 : 1;
save = reginput;
no = regrepeat(OPERAND(scan));
while (no >= min_no) {
// If it could work, try it.
if (nextch == '\0' || *reginput == nextch)
if (regmatch(next))
return (1);
// Couldn't or didn't -- back up.
no--;
reginput = save + no;
}
return (0);
}
// break;
case END:
return (1); // Success!
default:
// RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
printf(
"RegularExpression::find(): Internal error -- memory corrupted.\n");
return 0;
}
scan = next;
}
//
// We get here only if there's trouble -- normally "case END" is the
// terminating point.
//
// RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
printf("RegularExpression::find(): Internal error -- corrupted pointers.\n");
return (0);
}
/*
- regrepeat - repeatedly match something simple, report how many
*/
int RegExpFind::regrepeat(const char* p)
{
int count = 0;
const char* scan;
const char* opnd;
scan = reginput;
opnd = OPERAND(p);
switch (OP(p)) {
case ANY:
count = int(strlen(scan));
scan += count;
break;
case EXACTLY:
while (*opnd == *scan) {
count++;
scan++;
}
break;
case ANYOF:
while (*scan != '\0' && strchr(opnd, *scan) != nullptr) {
count++;
scan++;
}
break;
case ANYBUT:
while (*scan != '\0' && strchr(opnd, *scan) == nullptr) {
count++;
scan++;
}
break;
default: // Oh dear. Called inappropriately.
// RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
printf("cm RegularExpression::find(): Internal error.\n");
return 0;
}
reginput = scan;
return (count);
}
/*
- regnext - dig the "next" pointer out of a node
*/
static const char* regnext(const char* p)
{
int offset;
if (p == regdummyptr)
return (nullptr);
offset = NEXT(p);
if (offset == 0)
return (nullptr);
if (OP(p) == BACK)
return (p - offset);
else
return (p + offset);
}
static char* regnext(char* p)
{
int offset;
if (p == regdummyptr)
return (nullptr);
offset = NEXT(p);
if (offset == 0)
return (nullptr);
if (OP(p) == BACK)
return (p - offset);
else
return (p + offset);
}
} // namespace KWSYS_NAMESPACE
@@ -1,562 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
// Original Copyright notice:
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
// Created: MNF 06/13/89 Initial Design and Implementation
// Updated: LGO 08/09/89 Inherit from Generic
// Updated: MBN 09/07/89 Added conditional exception handling
// Updated: MBN 12/15/89 Sprinkled "const" qualifiers all over the place!
// Updated: DLS 03/22/91 New lite version
//
#ifndef @KWSYS_NAMESPACE@_RegularExpression_hxx
#define @KWSYS_NAMESPACE@_RegularExpression_hxx
#include <@KWSYS_NAMESPACE@/Configure.h>
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <string>
/* Disable useless Borland warnings. KWSys tries not to force things
on its includers, but there is no choice here. */
#if defined(__BORLANDC__)
# pragma warn - 8027 /* function not inlined. */
#endif
namespace @KWSYS_NAMESPACE@ {
// Forward declaration
class RegularExpression;
/** \class RegularExpressionMatch
* \brief Stores the pattern matches of a RegularExpression
*/
class @KWSYS_NAMESPACE@_EXPORT RegularExpressionMatch
{
public:
RegularExpressionMatch();
bool isValid() const;
void clear();
std::string::size_type start() const;
std::string::size_type end() const;
std::string::size_type start(int n) const;
std::string::size_type end(int n) const;
std::string match(int n) const;
enum
{
NSUBEXP = 10
};
private:
friend class RegularExpression;
const char* startp[NSUBEXP];
const char* endp[NSUBEXP];
const char* searchstring;
};
/**
* \brief Creates an invalid match object
*/
inline RegularExpressionMatch::RegularExpressionMatch()
: startp{}
, endp{}
, searchstring{}
{
}
/**
* \brief Returns true if the match pointers are valid
*/
inline bool RegularExpressionMatch::isValid() const
{
return (this->startp[0] != nullptr);
}
/**
* \brief Resets to the (invalid) construction state.
*/
inline void RegularExpressionMatch::clear()
{
startp[0] = nullptr;
endp[0] = nullptr;
searchstring = nullptr;
}
/**
* \brief Returns the start index of the full match.
*/
inline std::string::size_type RegularExpressionMatch::start() const
{
return static_cast<std::string::size_type>(this->startp[0] - searchstring);
}
/**
* \brief Returns the end index of the full match.
*/
inline std::string::size_type RegularExpressionMatch::end() const
{
return static_cast<std::string::size_type>(this->endp[0] - searchstring);
}
/**
* \brief Returns the start index of nth submatch.
* start(0) is the start of the full match.
*/
inline std::string::size_type RegularExpressionMatch::start(int n) const
{
return static_cast<std::string::size_type>(this->startp[n] -
this->searchstring);
}
/**
* \brief Returns the end index of nth submatch.
* end(0) is the end of the full match.
*/
inline std::string::size_type RegularExpressionMatch::end(int n) const
{
return static_cast<std::string::size_type>(this->endp[n] -
this->searchstring);
}
/**
* \brief Returns the nth submatch as a string.
*/
inline std::string RegularExpressionMatch::match(int n) const
{
if (this->startp[n] == nullptr) {
return std::string();
} else {
return std::string(
this->startp[n],
static_cast<std::string::size_type>(this->endp[n] - this->startp[n]));
}
}
/** \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 occurrence of the regular
* 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 indices 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
* nullptr, (i.e. there is no valid compiled expression). The set_invalid
* function sets the program to nullptr (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
* encountered 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 encountered in
* the line. It would match "drepa qrepb" in "rep drepa qrepb".
*
* All methods of RegularExpression can be called simultaneously from
* different threads but only if each invocation uses an own instance of
* RegularExpression.
*/
class @KWSYS_NAMESPACE@_EXPORT RegularExpression
{
public:
/**
* Instantiate RegularExpression with program=nullptr.
*/
inline RegularExpression();
/**
* Instantiate RegularExpression with compiled char*.
*/
inline RegularExpression(char const*);
/**
* Instantiate RegularExpression as a copy of another regular expression.
*/
RegularExpression(RegularExpression const&);
/**
* Instantiate RegularExpression with compiled string.
*/
inline RegularExpression(std::string const&);
/**
* Destructor.
*/
inline ~RegularExpression();
/**
* Compile a regular expression into internal code
* for later pattern matching.
*/
bool compile(char const*);
/**
* Compile a regular expression into internal code
* for later pattern matching.
*/
inline bool compile(std::string const&);
/**
* Matches the regular expression to the given string.
* Returns true if found, and sets start and end indexes
* in the RegularExpressionMatch instance accordingly.
*
* This method is thread safe when called with different
* RegularExpressionMatch instances.
*/
bool find(char const*, RegularExpressionMatch&) const;
/**
* Matches the regular expression to the given string.
* Returns true if found, and sets start and end indexes accordingly.
*/
inline bool find(char const*);
/**
* Matches the regular expression to the given std string.
* Returns true if found, and sets start and end indexes accordingly.
*/
inline bool find(std::string const&);
/**
* Match indices
*/
inline RegularExpressionMatch const& regMatch() const;
inline std::string::size_type start() const;
inline std::string::size_type end() const;
inline std::string::size_type start(int n) const;
inline std::string::size_type end(int n) const;
/**
* Match strings
*/
inline std::string match(int n) 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();
private:
RegularExpressionMatch regmatch;
char regstart; // Internal use only
char reganch; // Internal use only
const char* regmust; // Internal use only
std::string::size_type regmlen; // Internal use only
char* program;
int progsize;
};
/**
* Create an empty regular expression.
*/
inline RegularExpression::RegularExpression()
: regstart{}
, reganch{}
, regmust{}
, program{ nullptr }
, progsize{}
{
}
/**
* Creates a regular expression from string s, and
* compiles s.
*/
inline RegularExpression::RegularExpression(const char* s)
: regstart{}
, reganch{}
, regmust{}
, program{ nullptr }
, progsize{}
{
if (s) {
this->compile(s);
}
}
/**
* Creates a regular expression from string s, and
* compiles s.
*/
inline RegularExpression::RegularExpression(const std::string& s)
: regstart{}
, reganch{}
, regmust{}
, program{ nullptr }
, progsize{}
{
this->compile(s);
}
/**
* Destroys and frees space allocated for the regular expression.
*/
inline RegularExpression::~RegularExpression()
{
//#ifndef _WIN32
delete[] this->program;
//#endif
}
/**
* Compile a regular expression into internal code
* for later pattern matching.
*/
inline bool RegularExpression::compile(std::string const& s)
{
return this->compile(s.c_str());
}
/**
* Matches the regular expression to the given std string.
* Returns true if found, and sets start and end indexes accordingly.
*/
inline bool RegularExpression::find(const char* s)
{
return this->find(s, this->regmatch);
}
/**
* Matches the regular expression to the given std string.
* Returns true if found, and sets start and end indexes accordingly.
*/
inline bool RegularExpression::find(std::string const& s)
{
return this->find(s.c_str());
}
/**
* Returns the internal match object
*/
inline RegularExpressionMatch const& RegularExpression::regMatch() const
{
return this->regmatch;
}
/**
* Returns the start index of the full match.
*/
inline std::string::size_type RegularExpression::start() const
{
return regmatch.start();
}
/**
* Returns the end index of the full match.
*/
inline std::string::size_type RegularExpression::end() const
{
return regmatch.end();
}
/**
* Return start index of nth submatch. start(0) is the start of the full match.
*/
inline std::string::size_type RegularExpression::start(int n) const
{
return regmatch.start(n);
}
/**
* Return end index of nth submatch. end(0) is the end of the full match.
*/
inline std::string::size_type RegularExpression::end(int n) const
{
return regmatch.end(n);
}
/**
* Return nth submatch as a string.
*/
inline std::string RegularExpression::match(int n) const
{
return regmatch.match(n);
}
/**
* 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 != nullptr);
}
inline void RegularExpression::set_invalid()
{
//#ifndef _WIN32
delete[] this->program;
//#endif
this->program = nullptr;
}
} // namespace @KWSYS_NAMESPACE@
#endif
@@ -1,20 +0,0 @@
#!/usr/bin/env bash
cd "${BASH_SOURCE%/*}" &&
GitSetup/setup-user && echo &&
GitSetup/setup-hooks && echo &&
GitSetup/setup-aliases && echo &&
GitSetup/setup-upstream && echo &&
GitSetup/tips
# Rebase master by default
git config rebase.stat true
git config branch.master.rebase true
# Disable Gerrit hook explicitly so the commit-msg hook will
# not complain even if some gerrit remotes are still configured.
git config hooks.GerritId false
# Record the version of this setup so Scripts/pre-commit can check it.
SetupForDevelopment_VERSION=2
git config hooks.SetupForDevelopment ${SetupForDevelopment_VERSION}
-879
View File
@@ -1,879 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_SharedForward_h
# define @KWSYS_NAMESPACE@_SharedForward_h
/*
This header is used to create a forwarding executable sets up the
shared library search path and replaces itself with a real
executable. This is useful when creating installations on UNIX with
shared libraries that will run from any install directory. Typical
usage:
#if defined(CMAKE_INTDIR)
# define CONFIG_DIR_PRE CMAKE_INTDIR "/"
# define CONFIG_DIR_POST "/" CMAKE_INTDIR
#else
# define CONFIG_DIR_PRE ""
# define CONFIG_DIR_POST ""
#endif
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "/path/to/foo-build/bin"
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL "../lib/foo-1.2"
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD CONFIG_DIR_PRE "foo-real"
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL
"../lib/foo-1.2/foo-real"
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command"
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print"
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd"
#if defined(CMAKE_INTDIR)
# define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR
#endif
#include <@KWSYS_NAMESPACE@/SharedForward.h>
int main(int argc, char** argv)
{
return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv);
}
Specify search and executable paths relative to the forwarding
executable location or as full paths. Include no trailing slash.
In the case of a multi-configuration build, when CMAKE_INTDIR is
defined, the DIR_BUILD setting should point at the directory above
the executable (the one containing the per-configuration
subdirectory specified by CMAKE_INTDIR). Then PATH_BUILD entries
and EXE_BUILD should be specified relative to this location and use
CMAKE_INTDIR as necessary. In the above example imagine appending
the PATH_BUILD or EXE_BUILD setting to the DIR_BUILD setting. The
result should form a valid path with per-configuration subdirectory.
Additional paths may be specified in the PATH_BUILD and PATH_INSTALL
variables by using comma-separated strings. For example:
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD \
"." CONFIG_DIR_POST, "/path/to/bar-build" CONFIG_DIR_POST
#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL \
"../lib/foo-1.2", "../lib/bar-4.5"
See the comments below for specific explanations of each macro.
*/
/* Disable -Wcast-qual warnings since they are too hard to fix in a
cross-platform way. */
# if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wcast-qual")
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wcast-qual"
# endif
# endif
# if defined(__BORLANDC__) && !defined(__cplusplus)
/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an
unused parameter using "(param)" syntax (i.e. no cast to void). */
# pragma warn - 8019
# endif
/* Full path to the directory in which this executable is built. Do
not include a trailing slash. */
# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD)
# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD"
# endif
# if !defined(KWSYS_SHARED_FORWARD_DIR_BUILD)
# define KWSYS_SHARED_FORWARD_DIR_BUILD \
@KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD
# endif
/* Library search path for build tree. */
# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD)
# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD"
# endif
# if !defined(KWSYS_SHARED_FORWARD_PATH_BUILD)
# define KWSYS_SHARED_FORWARD_PATH_BUILD \
@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD
# endif
/* Library search path for install tree. */
# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL)
# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL"
# endif
# if !defined(KWSYS_SHARED_FORWARD_PATH_INSTALL)
# define KWSYS_SHARED_FORWARD_PATH_INSTALL \
@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL
# endif
/* The real executable to which to forward in the build tree. */
# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD)
# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD"
# endif
# if !defined(KWSYS_SHARED_FORWARD_EXE_BUILD)
# define KWSYS_SHARED_FORWARD_EXE_BUILD \
@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD
# endif
/* The real executable to which to forward in the install tree. */
# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL)
# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL"
# endif
# if !defined(KWSYS_SHARED_FORWARD_EXE_INSTALL)
# define KWSYS_SHARED_FORWARD_EXE_INSTALL \
@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL
# endif
/* The configuration name with which this executable was built (Debug/Release).
*/
# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME)
# define KWSYS_SHARED_FORWARD_CONFIG_NAME \
@KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME
# else
# undef KWSYS_SHARED_FORWARD_CONFIG_NAME
# endif
/* Create command line option to replace executable. */
# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND)
# if !defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND)
# define KWSYS_SHARED_FORWARD_OPTION_COMMAND \
@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND
# endif
# else
# undef KWSYS_SHARED_FORWARD_OPTION_COMMAND
# endif
/* Create command line option to print environment setting and exit. */
# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT)
# if !defined(KWSYS_SHARED_FORWARD_OPTION_PRINT)
# define KWSYS_SHARED_FORWARD_OPTION_PRINT \
@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT
# endif
# else
# undef KWSYS_SHARED_FORWARD_OPTION_PRINT
# endif
/* Create command line option to run ldd or equivalent. */
# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD)
# if !defined(KWSYS_SHARED_FORWARD_OPTION_LDD)
# define KWSYS_SHARED_FORWARD_OPTION_LDD \
@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD
# endif
# else
# undef KWSYS_SHARED_FORWARD_OPTION_LDD
# endif
/* Include needed system headers. */
# include <errno.h>
# include <limits.h>
# include <stddef.h> /* size_t */
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# if defined(_WIN32) && !defined(__CYGWIN__)
# include <windows.h>
# include <io.h>
# include <process.h>
# define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */
# else
# include <sys/stat.h>
# include <unistd.h>
# endif
/* Configuration for this platform. */
/* The path separator for this platform. */
# if defined(_WIN32) && !defined(__CYGWIN__)
# define KWSYS_SHARED_FORWARD_PATH_SEP ';'
# define KWSYS_SHARED_FORWARD_PATH_SLASH '\\'
# else
# define KWSYS_SHARED_FORWARD_PATH_SEP ':'
# define KWSYS_SHARED_FORWARD_PATH_SLASH '/'
# endif
static const char kwsys_shared_forward_path_sep[2] = {
KWSYS_SHARED_FORWARD_PATH_SEP, 0
};
static const char kwsys_shared_forward_path_slash[2] = {
KWSYS_SHARED_FORWARD_PATH_SLASH, 0
};
/* The maximum length of a file name. */
# if defined(PATH_MAX)
# define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX
# elif defined(MAXPATHLEN)
# define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN
# else
# define KWSYS_SHARED_FORWARD_MAXPATH 16384
# endif
/* Select the environment variable holding the shared library runtime
search path for this platform and build configuration. Also select
ldd command equivalent. */
/* Linux */
# if defined(__linux)
# define KWSYS_SHARED_FORWARD_LDD "ldd"
# define KWSYS_SHARED_FORWARD_LDD_N 1
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
/* FreeBSD */
# elif defined(__FreeBSD__)
# define KWSYS_SHARED_FORWARD_LDD "ldd"
# define KWSYS_SHARED_FORWARD_LDD_N 1
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
/* OpenBSD */
# elif defined(__OpenBSD__)
# define KWSYS_SHARED_FORWARD_LDD "ldd"
# define KWSYS_SHARED_FORWARD_LDD_N 1
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
/* OS X */
# elif defined(__APPLE__)
# define KWSYS_SHARED_FORWARD_LDD "otool", "-L"
# define KWSYS_SHARED_FORWARD_LDD_N 2
# define KWSYS_SHARED_FORWARD_LDPATH "DYLD_LIBRARY_PATH"
/* AIX */
# elif defined(_AIX)
# define KWSYS_SHARED_FORWARD_LDD "dump", "-H"
# define KWSYS_SHARED_FORWARD_LDD_N 2
# define KWSYS_SHARED_FORWARD_LDPATH "LIBPATH"
/* SUN */
# elif defined(__sun)
# define KWSYS_SHARED_FORWARD_LDD "ldd"
# define KWSYS_SHARED_FORWARD_LDD_N 1
# include <sys/isa_defs.h>
# if defined(_ILP32)
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
# elif defined(_LP64)
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64"
# endif
/* HP-UX */
# elif defined(__hpux)
# define KWSYS_SHARED_FORWARD_LDD "chatr"
# define KWSYS_SHARED_FORWARD_LDD_N 1
# if defined(__LP64__)
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
# else
# define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH"
# endif
/* SGI MIPS */
# elif defined(__sgi) && defined(_MIPS_SIM)
# define KWSYS_SHARED_FORWARD_LDD "ldd"
# define KWSYS_SHARED_FORWARD_LDD_N 1
# if _MIPS_SIM == _ABIO32
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
# elif _MIPS_SIM == _ABIN32
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH"
# elif _MIPS_SIM == _ABI64
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH"
# endif
/* Cygwin */
# elif defined(__CYGWIN__)
# define KWSYS_SHARED_FORWARD_LDD \
"cygcheck" /* TODO: cygwin 1.7 has ldd \
*/
# define KWSYS_SHARED_FORWARD_LDD_N 1
# define KWSYS_SHARED_FORWARD_LDPATH "PATH"
/* Windows */
# elif defined(_WIN32)
# define KWSYS_SHARED_FORWARD_LDPATH "PATH"
/* Guess on this unknown system. */
# else
# define KWSYS_SHARED_FORWARD_LDD "ldd"
# define KWSYS_SHARED_FORWARD_LDD_N 1
# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
# endif
# ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV
typedef struct kwsys_sf_arg_info_s
{
const char* arg;
int size;
int quote;
} kwsys_sf_arg_info;
static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in)
{
/* Initialize information. */
kwsys_sf_arg_info info;
/* String iterator. */
const char* c;
/* Keep track of how many backslashes have been encountered in a row. */
int windows_backslashes = 0;
/* Start with the length of the original argument, plus one for
either a terminating null or a separating space. */
info.arg = in;
info.size = (int)strlen(in) + 1;
info.quote = 0;
/* Scan the string for characters that require escaping or quoting. */
for (c = in; *c; ++c) {
/* Check whether this character needs quotes. */
if (strchr(" \t?'#&<>|^", *c)) {
info.quote = 1;
}
/* On Windows only backslashes and double-quotes need escaping. */
if (*c == '\\') {
/* Found a backslash. It may need to be escaped later. */
++windows_backslashes;
} else if (*c == '"') {
/* Found a double-quote. We need to escape it and all
immediately preceding backslashes. */
info.size += windows_backslashes + 1;
windows_backslashes = 0;
} else {
/* Found another character. This eliminates the possibility
that any immediately preceding backslashes will be
escaped. */
windows_backslashes = 0;
}
}
/* Check whether the argument needs surrounding quotes. */
if (info.quote) {
/* Surrounding quotes are needed. Allocate space for them. */
info.size += 2;
/* We must escape all ending backslashes when quoting on windows. */
info.size += windows_backslashes;
}
return info;
}
static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out)
{
/* String iterator. */
const char* c;
/* Keep track of how many backslashes have been encountered in a row. */
int windows_backslashes = 0;
/* Whether the argument must be quoted. */
if (info.quote) {
/* Add the opening quote for this argument. */
*out++ = '"';
}
/* Scan the string for characters that require escaping or quoting. */
for (c = info.arg; *c; ++c) {
/* On Windows only backslashes and double-quotes need escaping. */
if (*c == '\\') {
/* Found a backslash. It may need to be escaped later. */
++windows_backslashes;
} else if (*c == '"') {
/* Found a double-quote. Escape all immediately preceding
backslashes. */
while (windows_backslashes > 0) {
--windows_backslashes;
*out++ = '\\';
}
/* Add the backslash to escape the double-quote. */
*out++ = '\\';
} else {
/* We encountered a normal character. This eliminates any
escaping needed for preceding backslashes. */
windows_backslashes = 0;
}
/* Store this character. */
*out++ = *c;
}
if (info.quote) {
/* Add enough backslashes to escape any trailing ones. */
while (windows_backslashes > 0) {
--windows_backslashes;
*out++ = '\\';
}
/* Add the closing quote for this argument. */
*out++ = '"';
}
/* Store a terminating null without incrementing. */
*out = 0;
return out;
}
# endif
/* Function to convert a logical or relative path to a physical full path. */
static int kwsys_shared_forward_realpath(const char* in_path, char* out_path)
{
# if defined(_WIN32) && !defined(__CYGWIN__)
/* Implementation for Windows. */
DWORD n =
GetFullPathNameA(in_path, KWSYS_SHARED_FORWARD_MAXPATH, out_path, 0);
return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH;
# else
/* Implementation for UNIX. */
return realpath(in_path, out_path) != 0;
# endif
}
static int kwsys_shared_forward_samepath(const char* file1, const char* file2)
{
# if defined(_WIN32)
int result = 0;
HANDLE h1 = CreateFileA(file1, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
HANDLE h2 = CreateFileA(file2, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE) {
BY_HANDLE_FILE_INFORMATION fi1;
BY_HANDLE_FILE_INFORMATION fi2;
GetFileInformationByHandle(h1, &fi1);
GetFileInformationByHandle(h2, &fi2);
result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
fi1.nFileIndexLow == fi2.nFileIndexLow);
}
CloseHandle(h1);
CloseHandle(h2);
return result;
# else
struct stat fs1, fs2;
return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 &&
memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 &&
memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 &&
fs2.st_size == fs1.st_size);
# endif
}
/* Function to report a system error message. */
static void kwsys_shared_forward_strerror(char* message)
{
# if defined(_WIN32) && !defined(__CYGWIN__)
/* Implementation for Windows. */
DWORD original = GetLastError();
DWORD length =
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, original, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
message, KWSYS_SHARED_FORWARD_MAXPATH, 0);
if (length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) {
/* FormatMessage failed. Use a default message. */
_snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH,
"Error 0x%X (FormatMessage failed with error 0x%X)", original,
GetLastError());
}
# else
/* Implementation for UNIX. */
strcpy(message, strerror(errno));
# endif
}
/* Functions to execute a child process. */
static void kwsys_shared_forward_execvp(const char* cmd,
char const* const* argv)
{
# ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV
/* Count the number of arguments. */
int argc = 0;
{
char const* const* argvc;
for (argvc = argv; *argvc; ++argvc, ++argc) {
}
}
/* Create the escaped arguments. */
{
char** nargv = (char**)malloc((argc + 1) * sizeof(char*));
int i;
for (i = 0; i < argc; ++i) {
kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]);
nargv[i] = (char*)malloc(info.size);
kwsys_sf_get_arg(info, nargv[i]);
}
nargv[argc] = 0;
/* Replace the command line to be used. */
argv = (char const* const*)nargv;
}
# endif
/* Invoke the child process. */
# if defined(_MSC_VER)
_execvp(cmd, argv);
# elif defined(__MINGW32__) && !defined(__MINGW64__)
execvp(cmd, argv);
# else
execvp(cmd, (char* const*)argv);
# endif
}
/* Function to get the directory containing the given file or directory. */
static void kwsys_shared_forward_dirname(const char* begin, char* result)
{
/* Find the location of the last slash. */
int last_slash_index = -1;
const char* end = begin + strlen(begin);
for (; begin <= end && last_slash_index < 0; --end) {
if (*end == '/' || *end == '\\') {
last_slash_index = (int)(end - begin);
}
}
/* Handle each case of the index of the last slash. */
if (last_slash_index < 0) {
/* No slashes. */
strcpy(result, ".");
} else if (last_slash_index == 0) {
/* Only one leading slash. */
strcpy(result, kwsys_shared_forward_path_slash);
}
# if defined(_WIN32)
else if (last_slash_index == 2 && begin[1] == ':') {
/* Only one leading drive letter and slash. */
strncpy(result, begin, (size_t)last_slash_index);
result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH;
result[last_slash_index + 1] = 0;
}
# endif
else {
/* A non-leading slash. */
strncpy(result, begin, (size_t)last_slash_index);
result[last_slash_index] = 0;
}
}
/* Function to check if a file exists and is executable. */
static int kwsys_shared_forward_is_executable(const char* f)
{
# if defined(_MSC_VER)
# define KWSYS_SHARED_FORWARD_ACCESS _access
# else
# define KWSYS_SHARED_FORWARD_ACCESS access
# endif
# if defined(X_OK)
# define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK
# else
# define KWSYS_SHARED_FORWARD_ACCESS_OK 04
# endif
if (KWSYS_SHARED_FORWARD_ACCESS(f, KWSYS_SHARED_FORWARD_ACCESS_OK) == 0) {
return 1;
} else {
return 0;
}
}
/* Function to locate the executable currently running. */
static int kwsys_shared_forward_self_path(const char* argv0, char* result)
{
/* Check whether argv0 has a slash. */
int has_slash = 0;
const char* p = argv0;
for (; *p && !has_slash; ++p) {
if (*p == '/' || *p == '\\') {
has_slash = 1;
}
}
if (has_slash) {
/* There is a slash. Use the dirname of the given location. */
kwsys_shared_forward_dirname(argv0, result);
return 1;
} else {
/* There is no slash. Search the PATH for the executable. */
const char* path = getenv("PATH");
const char* begin = path;
const char* end = begin + (begin ? strlen(begin) : 0);
const char* first = begin;
while (first != end) {
/* Store the end of this path entry. */
const char* last;
/* Skip all path separators. */
for (; *first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first)
;
/* Find the next separator. */
for (last = first; *last && *last != KWSYS_SHARED_FORWARD_PATH_SEP;
++last)
;
/* If we got a non-empty directory, look for the executable there. */
if (first < last) {
/* Determine the length without trailing slash. */
size_t length = (size_t)(last - first);
if (*(last - 1) == '/' || *(last - 1) == '\\') {
--length;
}
/* Construct the name of the executable in this location. */
strncpy(result, first, length);
result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH;
strcpy(result + (length) + 1, argv0);
/* Check if it exists and is executable. */
if (kwsys_shared_forward_is_executable(result)) {
/* Found it. */
result[length] = 0;
return 1;
}
}
/* Move to the next directory in the path. */
first = last;
}
}
/* We could not find the executable. */
return 0;
}
/* Function to convert a specified path to a full path. If it is not
already full, it is taken relative to the self path. */
static int kwsys_shared_forward_fullpath(const char* self_path,
const char* in_path, char* result,
const char* desc)
{
/* Check the specified path type. */
if (in_path[0] == '/') {
/* Already a full path. */
strcpy(result, in_path);
}
# if defined(_WIN32)
else if (in_path[0] && in_path[1] == ':') {
/* Already a full path. */
strcpy(result, in_path);
}
# endif
else {
/* Relative to self path. */
char temp_path[KWSYS_SHARED_FORWARD_MAXPATH];
strcpy(temp_path, self_path);
strcat(temp_path, kwsys_shared_forward_path_slash);
strcat(temp_path, in_path);
if (!kwsys_shared_forward_realpath(temp_path, result)) {
if (desc) {
char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH];
kwsys_shared_forward_strerror(msgbuf);
fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", desc,
temp_path, msgbuf);
}
return 0;
}
}
return 1;
}
/* Function to compute the library search path and executable name
based on the self path. */
static int kwsys_shared_forward_get_settings(const char* self_path,
char* ldpath, char* exe)
{
/* Possible search paths. */
static const char* search_path_build[] = { KWSYS_SHARED_FORWARD_PATH_BUILD,
0 };
static const char* search_path_install[] = {
KWSYS_SHARED_FORWARD_PATH_INSTALL, 0
};
/* Chosen paths. */
const char** search_path;
const char* exe_path;
/* Get the real name of the build and self paths. */
# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
char build_path[] =
KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME;
char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH];
# else
char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD;
const char* self_path_logical = self_path;
# endif
char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH];
char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH];
if (!kwsys_shared_forward_realpath(self_path, self_path_real)) {
char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH];
kwsys_shared_forward_strerror(msgbuf);
fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n",
self_path, msgbuf);
return 0;
}
/* Check whether we are running in the build tree or an install tree. */
if (kwsys_shared_forward_realpath(build_path, build_path_real) &&
kwsys_shared_forward_samepath(self_path_real, build_path_real)) {
/* Running in build tree. Use the build path and exe. */
search_path = search_path_build;
# if defined(_WIN32)
exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe";
# else
exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD;
# endif
# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
/* Remove the configuration directory from self_path. */
kwsys_shared_forward_dirname(self_path, self_path_logical);
# endif
} else {
/* Running in install tree. Use the install path and exe. */
search_path = search_path_install;
# if defined(_WIN32)
exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe";
# else
exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL;
# endif
# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
/* Use the original self path directory. */
strcpy(self_path_logical, self_path);
# endif
}
/* Construct the runtime search path. */
{
const char** dir;
for (dir = search_path; *dir; ++dir) {
/* Add separator between path components. */
if (dir != search_path) {
strcat(ldpath, kwsys_shared_forward_path_sep);
}
/* Add this path component. */
if (!kwsys_shared_forward_fullpath(self_path_logical, *dir,
ldpath + strlen(ldpath),
"runtime path entry")) {
return 0;
}
}
}
/* Construct the executable location. */
if (!kwsys_shared_forward_fullpath(self_path_logical, exe_path, exe,
"executable file")) {
return 0;
}
return 1;
}
/* Function to print why execution of a command line failed. */
static void kwsys_shared_forward_print_failure(char const* const* argv)
{
char msg[KWSYS_SHARED_FORWARD_MAXPATH];
char const* const* arg = argv;
kwsys_shared_forward_strerror(msg);
fprintf(stderr, "Error running");
for (; *arg; ++arg) {
fprintf(stderr, " \"%s\"", *arg);
}
fprintf(stderr, ": %s\n", msg);
}
/* Static storage space to store the updated environment variable. */
static char kwsys_shared_forward_ldpath[65535] =
KWSYS_SHARED_FORWARD_LDPATH "=";
/* Main driver function to be called from main. */
static int @KWSYS_NAMESPACE@_shared_forward_to_real(int argc, char** argv_in)
{
char const** argv = (char const**)argv_in;
/* Get the directory containing this executable. */
char self_path[KWSYS_SHARED_FORWARD_MAXPATH];
if (kwsys_shared_forward_self_path(argv[0], self_path)) {
/* Found this executable. Use it to get the library directory. */
char exe[KWSYS_SHARED_FORWARD_MAXPATH];
if (kwsys_shared_forward_get_settings(self_path,
kwsys_shared_forward_ldpath, exe)) {
/* Append the old runtime search path. */
const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH);
if (old_ldpath) {
strcat(kwsys_shared_forward_ldpath, kwsys_shared_forward_path_sep);
strcat(kwsys_shared_forward_ldpath, old_ldpath);
}
/* Store the environment variable. */
putenv(kwsys_shared_forward_ldpath);
# if defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND)
/* Look for the command line replacement option. */
if (argc > 1 &&
strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0) {
if (argc > 2) {
/* Use the command line given. */
strcpy(exe, argv[2]);
argv += 2;
argc -= 2;
} else {
/* The option was not given an executable. */
fprintf(stderr,
"Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND
" must be followed by a command line.\n");
return 1;
}
}
# endif
# if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT)
/* Look for the print command line option. */
if (argc > 1 &&
strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0) {
fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath);
fprintf(stdout, "%s\n", exe);
return 0;
}
# endif
# if defined(KWSYS_SHARED_FORWARD_OPTION_LDD)
/* Look for the ldd command line option. */
if (argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0) {
# if defined(KWSYS_SHARED_FORWARD_LDD)
/* Use the named ldd-like executable and arguments. */
char const* ldd_argv[] = { KWSYS_SHARED_FORWARD_LDD, 0, 0 };
ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe;
kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv);
/* Report why execution failed. */
kwsys_shared_forward_print_failure(ldd_argv);
return 1;
# else
/* We have no ldd-like executable available on this platform. */
fprintf(stderr, "No ldd-like tool is known to this executable.\n");
return 1;
# endif
}
# endif
/* Replace this process with the real executable. */
argv[0] = exe;
kwsys_shared_forward_execvp(argv[0], argv);
/* Report why execution failed. */
kwsys_shared_forward_print_failure(argv);
} else {
/* Could not convert self path to the library directory. */
}
} else {
/* Could not find this executable. */
fprintf(stderr, "Error locating executable \"%s\".\n", argv[0]);
}
/* Avoid unused argument warning. */
(void)argc;
/* Exit with failure. */
return 1;
}
/* Restore warning stack. */
# if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wcast-qual")
# pragma clang diagnostic pop
# endif
# endif
#else
# error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once."
#endif
-100
View File
@@ -1,100 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifdef KWSYS_STRING_C
/*
All code in this source file is conditionally compiled to work-around
template definition auto-search on VMS. Other source files in this
directory that use the stl string cause the compiler to load this
source to try to get the definition of the string template. This
condition blocks the compiler from seeing the symbols defined here.
*/
# include "kwsysPrivate.h"
# include KWSYS_HEADER(String.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
# if 0
# include "String.h.in"
# endif
/* Select an implementation for strcasecmp. */
# if defined(_MSC_VER)
# define KWSYS_STRING_USE_STRICMP
# include <string.h>
# elif defined(__GNUC__)
# define KWSYS_STRING_USE_STRCASECMP
# include <strings.h>
# else
/* Table to convert upper case letters to lower case and leave all
other characters alone. */
static char kwsysString_strcasecmp_tolower[] = {
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010',
'\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021',
'\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032',
'\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043',
'\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054',
'\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065',
'\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076',
'\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160',
'\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171',
'\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142',
'\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153',
'\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164',
'\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175',
'\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206',
'\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230',
'\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241',
'\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252',
'\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263',
'\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274',
'\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305',
'\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316',
'\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340',
'\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351',
'\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362',
'\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373',
'\374', '\375', '\376', '\377'
};
# endif
/*--------------------------------------------------------------------------*/
int kwsysString_strcasecmp(const char* lhs, const char* rhs)
{
# if defined(KWSYS_STRING_USE_STRICMP)
return _stricmp(lhs, rhs);
# elif defined(KWSYS_STRING_USE_STRCASECMP)
return strcasecmp(lhs, rhs);
# else
const char* const lower = kwsysString_strcasecmp_tolower;
unsigned char const* us1 = (unsigned char const*)lhs;
unsigned char const* us2 = (unsigned char const*)rhs;
int result;
while ((result = lower[*us1] - lower[*us2++], result == 0) && *us1++) {
}
return result;
# endif
}
/*--------------------------------------------------------------------------*/
int kwsysString_strncasecmp(const char* lhs, const char* rhs, size_t n)
{
# if defined(KWSYS_STRING_USE_STRICMP)
return _strnicmp(lhs, rhs, n);
# elif defined(KWSYS_STRING_USE_STRCASECMP)
return strncasecmp(lhs, rhs, n);
# else
const char* const lower = kwsysString_strcasecmp_tolower;
unsigned char const* us1 = (unsigned char const*)lhs;
unsigned char const* us2 = (unsigned char const*)rhs;
int result = 0;
while (n && (result = lower[*us1] - lower[*us2++], result == 0) && *us1++) {
--n;
}
return result;
# endif
}
#endif /* KWSYS_STRING_C */
-57
View File
@@ -1,57 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_String_h
#define @KWSYS_NAMESPACE@_String_h
#include <@KWSYS_NAMESPACE@/Configure.h>
#include <stddef.h> /* size_t */
/* Redefine all public interface symbol names to be in the proper
namespace. These macros are used internally to kwsys only, and are
not visible to user code. Use kwsysHeaderDump.pl to reproduce
these macros after making changes to the interface. */
#if !defined(KWSYS_NAMESPACE)
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsysString_strcasecmp kwsys_ns(String_strcasecmp)
# define kwsysString_strncasecmp kwsys_ns(String_strncasecmp)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/**
* Compare two strings ignoring the case of the characters. The
* integer returned is negative, zero, or positive if the first string
* is found to be less than, equal to, or greater than the second
* string, respectively.
*/
kwsysEXPORT int kwsysString_strcasecmp(const char* lhs, const char* rhs);
/**
* Identical to String_strcasecmp except that only the first n
* characters are considered.
*/
kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs,
size_t n);
#if defined(__cplusplus)
} /* extern "C" */
#endif
/* If we are building a kwsys .c or .cxx file, let it use these macros.
Otherwise, undefine them to keep the namespace clean. */
#if !defined(KWSYS_NAMESPACE)
# undef kwsys_ns
# undef kwsysEXPORT
# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# undef kwsysString_strcasecmp
# undef kwsysString_strncasecmp
# endif
#endif
#endif
-65
View File
@@ -1,65 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_String_hxx
#define @KWSYS_NAMESPACE@_String_hxx
#include <string>
namespace @KWSYS_NAMESPACE@ {
/** \class String
* \brief Short-name version of the STL basic_string class template.
*
* The standard library "string" type is actually a typedef for
* "basic_string<..long argument list..>". This string class is
* simply a subclass of this type with the same interface so that the
* name is shorter in debugging symbols and error messages.
*/
class String : public std::string
{
/** The original string type. */
typedef std::string stl_string;
public:
/** String member types. */
typedef stl_string::value_type value_type;
typedef stl_string::pointer pointer;
typedef stl_string::reference reference;
typedef stl_string::const_reference const_reference;
typedef stl_string::size_type size_type;
typedef stl_string::difference_type difference_type;
typedef stl_string::iterator iterator;
typedef stl_string::const_iterator const_iterator;
typedef stl_string::reverse_iterator reverse_iterator;
typedef stl_string::const_reverse_iterator const_reverse_iterator;
/** String constructors. */
String()
: stl_string()
{
}
String(const value_type* s)
: stl_string(s)
{
}
String(const value_type* s, size_type n)
: stl_string(s, n)
{
}
String(const stl_string& s, size_type pos = 0, size_type n = npos)
: stl_string(s, pos, n)
{
}
}; // End Class: String
#if defined(__WATCOMC__)
inline bool operator<(String const& l, String const& r)
{
return (static_cast<std::string const&>(l) <
static_cast<std::string const&>(r));
}
#endif
} // namespace @KWSYS_NAMESPACE@
#endif
-236
View File
@@ -1,236 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(System.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
#if 0
# include "System.h.in"
#endif
#include <ctype.h> /* isspace */
#include <stddef.h> /* ptrdiff_t */
#include <stdlib.h> /* malloc, free */
#include <string.h> /* memcpy */
#include <stdio.h>
#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T
typedef ptrdiff_t kwsysSystem_ptrdiff_t;
#else
typedef int kwsysSystem_ptrdiff_t;
#endif
static int kwsysSystem__AppendByte(char* local, char** begin, char** end,
int* size, char c)
{
/* Allocate space for the character. */
if ((*end - *begin) >= *size) {
kwsysSystem_ptrdiff_t length = *end - *begin;
char* newBuffer = (char*)malloc((size_t)(*size * 2));
if (!newBuffer) {
return 0;
}
memcpy(newBuffer, *begin, (size_t)(length) * sizeof(char));
if (*begin != local) {
free(*begin);
}
*begin = newBuffer;
*end = *begin + length;
*size *= 2;
}
/* Store the character. */
*(*end)++ = c;
return 1;
}
static int kwsysSystem__AppendArgument(char** local, char*** begin,
char*** end, int* size, char* arg_local,
char** arg_begin, char** arg_end,
int* arg_size)
{
/* Append a null-terminator to the argument string. */
if (!kwsysSystem__AppendByte(arg_local, arg_begin, arg_end, arg_size,
'\0')) {
return 0;
}
/* Allocate space for the argument pointer. */
if ((*end - *begin) >= *size) {
kwsysSystem_ptrdiff_t length = *end - *begin;
char** newPointers = (char**)malloc((size_t)(*size) * 2 * sizeof(char*));
if (!newPointers) {
return 0;
}
memcpy(newPointers, *begin, (size_t)(length) * sizeof(char*));
if (*begin != local) {
free(*begin);
}
*begin = newPointers;
*end = *begin + length;
*size *= 2;
}
/* Allocate space for the argument string. */
**end = (char*)malloc((size_t)(*arg_end - *arg_begin));
if (!**end) {
return 0;
}
/* Store the argument in the command array. */
memcpy(**end, *arg_begin, (size_t)(*arg_end - *arg_begin));
++(*end);
/* Reset the argument to be empty. */
*arg_end = *arg_begin;
return 1;
}
#define KWSYSPE_LOCAL_BYTE_COUNT 1024
#define KWSYSPE_LOCAL_ARGS_COUNT 32
static char** kwsysSystem__ParseUnixCommand(const char* command, int flags)
{
/* Create a buffer for argument pointers during parsing. */
char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT];
int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT;
char** pointer_begin = local_pointers;
char** pointer_end = pointer_begin;
/* Create a buffer for argument strings during parsing. */
char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT];
int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT;
char* buffer_begin = local_buffer;
char* buffer_end = buffer_begin;
/* Parse the command string. Try to behave like a UNIX shell. */
char** newCommand = 0;
const char* c = command;
int in_argument = 0;
int in_escape = 0;
int in_single = 0;
int in_double = 0;
int failed = 0;
for (; *c; ++c) {
if (in_escape) {
/* This character is escaped so do no special handling. */
if (!in_argument) {
in_argument = 1;
}
if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end,
&buffer_size, *c)) {
failed = 1;
break;
}
in_escape = 0;
} else if (*c == '\\') {
/* The next character should be escaped. */
in_escape = 1;
} else if (*c == '\'' && !in_double) {
/* Enter or exit single-quote state. */
if (in_single) {
in_single = 0;
} else {
in_single = 1;
if (!in_argument) {
in_argument = 1;
}
}
} else if (*c == '"' && !in_single) {
/* Enter or exit double-quote state. */
if (in_double) {
in_double = 0;
} else {
in_double = 1;
if (!in_argument) {
in_argument = 1;
}
}
} else if (isspace((unsigned char)*c)) {
if (in_argument) {
if (in_single || in_double) {
/* This space belongs to a quoted argument. */
if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin,
&buffer_end, &buffer_size, *c)) {
failed = 1;
break;
}
} else {
/* This argument has been terminated by whitespace. */
if (!kwsysSystem__AppendArgument(
local_pointers, &pointer_begin, &pointer_end, &pointers_size,
local_buffer, &buffer_begin, &buffer_end, &buffer_size)) {
failed = 1;
break;
}
in_argument = 0;
}
}
} else {
/* This character belong to an argument. */
if (!in_argument) {
in_argument = 1;
}
if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end,
&buffer_size, *c)) {
failed = 1;
break;
}
}
}
/* Finish the last argument. */
if (in_argument) {
if (!kwsysSystem__AppendArgument(
local_pointers, &pointer_begin, &pointer_end, &pointers_size,
local_buffer, &buffer_begin, &buffer_end, &buffer_size)) {
failed = 1;
}
}
/* If we still have memory allocate space for the new command
buffer. */
if (!failed) {
kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin;
newCommand = (char**)malloc((size_t)(n + 1) * sizeof(char*));
}
if (newCommand) {
/* Copy the arguments into the new command buffer. */
kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin;
memcpy(newCommand, pointer_begin, sizeof(char*) * (size_t)(n));
newCommand[n] = 0;
} else {
/* Free arguments already allocated. */
while (pointer_end != pointer_begin) {
free(*(--pointer_end));
}
}
/* Free temporary buffers. */
if (pointer_begin != local_pointers) {
free(pointer_begin);
}
if (buffer_begin != local_buffer) {
free(buffer_begin);
}
/* The flags argument is currently unused. */
(void)flags;
/* Return the final command buffer. */
return newCommand;
}
char** kwsysSystem_Parse_CommandForUnix(const char* command, int flags)
{
/* Validate the flags. */
if (flags != 0) {
return 0;
}
/* Forward to our internal implementation. */
return kwsysSystem__ParseUnixCommand(command, flags);
}
-60
View File
@@ -1,60 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_System_h
#define @KWSYS_NAMESPACE@_System_h
#include <@KWSYS_NAMESPACE@/Configure.h>
/* Redefine all public interface symbol names to be in the proper
namespace. These macros are used internally to kwsys only, and are
not visible to user code. Use kwsysHeaderDump.pl to reproduce
these macros after making changes to the interface. */
#if !defined(KWSYS_NAMESPACE)
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsysSystem_Parse_CommandForUnix \
kwsys_ns(System_Parse_CommandForUnix)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/**
* Parse a unix-style command line string into separate arguments.
*
* On success, returns a pointer to an array of pointers to individual
* argument strings. Each string is null-terminated and the last
* entry in the array is a NULL pointer (just like argv). It is the
* caller's responsibility to free() the strings and the array of
* pointers to them.
*
* On failure, returns NULL. Failure occurs only on invalid flags or
* when memory cannot be allocated; never due to content of the input
* string. Missing close-quotes are treated as if the necessary
* closing quote appears.
*
* By default single- and double-quoted arguments are supported, and
* any character may be escaped by a backslash. The flags argument is
* reserved for future use, and must be zero (or the call will fail).
*/
kwsysEXPORT char** kwsysSystem_Parse_CommandForUnix(const char* command,
int flags);
#if defined(__cplusplus)
} /* extern "C" */
#endif
/* If we are building a kwsys .c or .cxx file, let it use these macros.
Otherwise, undefine them to keep the namespace clean. */
#if !defined(KWSYS_NAMESPACE)
# undef kwsys_ns
# undef kwsysEXPORT
# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# undef kwsysSystem_Parse_CommandForUnix
# endif
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -1,170 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_SystemInformation_h
#define @KWSYS_NAMESPACE@_SystemInformation_h
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <stddef.h> /* size_t */
#include <string>
namespace @KWSYS_NAMESPACE@ {
// forward declare the implementation class
class SystemInformationImplementation;
class @KWSYS_NAMESPACE@_EXPORT SystemInformation
{
#if @KWSYS_USE_LONG_LONG@
typedef long long LongLong;
#elif @KWSYS_USE___INT64@
typedef __int64 LongLong;
#else
# error "No Long Long"
#endif
friend class SystemInformationImplementation;
SystemInformationImplementation* Implementation;
public:
// possible parameter values for DoesCPUSupportFeature()
static const long int CPU_FEATURE_MMX = 1 << 0;
static const long int CPU_FEATURE_MMX_PLUS = 1 << 1;
static const long int CPU_FEATURE_SSE = 1 << 2;
static const long int CPU_FEATURE_SSE2 = 1 << 3;
static const long int CPU_FEATURE_AMD_3DNOW = 1 << 4;
static const long int CPU_FEATURE_AMD_3DNOW_PLUS = 1 << 5;
static const long int CPU_FEATURE_IA64 = 1 << 6;
static const long int CPU_FEATURE_MP_CAPABLE = 1 << 7;
static const long int CPU_FEATURE_HYPERTHREAD = 1 << 8;
static const long int CPU_FEATURE_SERIALNUMBER = 1 << 9;
static const long int CPU_FEATURE_APIC = 1 << 10;
static const long int CPU_FEATURE_SSE_FP = 1 << 11;
static const long int CPU_FEATURE_SSE_MMX = 1 << 12;
static const long int CPU_FEATURE_CMOV = 1 << 13;
static const long int CPU_FEATURE_MTRR = 1 << 14;
static const long int CPU_FEATURE_L1CACHE = 1 << 15;
static const long int CPU_FEATURE_L2CACHE = 1 << 16;
static const long int CPU_FEATURE_L3CACHE = 1 << 17;
static const long int CPU_FEATURE_ACPI = 1 << 18;
static const long int CPU_FEATURE_THERMALMONITOR = 1 << 19;
static const long int CPU_FEATURE_TEMPSENSEDIODE = 1 << 20;
static const long int CPU_FEATURE_FREQUENCYID = 1 << 21;
static const long int CPU_FEATURE_VOLTAGEID_FREQUENCY = 1 << 22;
static const long int CPU_FEATURE_FPU = 1 << 23;
public:
SystemInformation();
~SystemInformation();
SystemInformation(const SystemInformation&) = delete;
SystemInformation& operator=(const SystemInformation&) = delete;
const char* GetVendorString();
const char* GetVendorID();
std::string GetTypeID();
std::string GetFamilyID();
std::string GetModelID();
std::string GetModelName();
std::string GetSteppingCode();
const char* GetExtendedProcessorName();
const char* GetProcessorSerialNumber();
int GetProcessorCacheSize();
unsigned int GetLogicalProcessorsPerPhysical();
float GetProcessorClockFrequency();
int GetProcessorAPICID();
int GetProcessorCacheXSize(long int);
bool DoesCPUSupportFeature(long int);
// returns an informative general description of the cpu
// on this system.
std::string GetCPUDescription();
const char* GetHostname();
std::string GetFullyQualifiedDomainName();
const char* GetOSName();
const char* GetOSRelease();
const char* GetOSVersion();
const char* GetOSPlatform();
int GetOSIsWindows();
int GetOSIsLinux();
int GetOSIsApple();
// returns an informative general description of the os
// on this system.
std::string GetOSDescription();
// returns if the operating system is 64bit or not.
bool Is64Bits();
unsigned int GetNumberOfLogicalCPU();
unsigned int GetNumberOfPhysicalCPU();
bool DoesCPUSupportCPUID();
// Retrieve id of the current running process
LongLong GetProcessId();
// Retrieve memory information in MiB.
size_t GetTotalVirtualMemory();
size_t GetAvailableVirtualMemory();
size_t GetTotalPhysicalMemory();
size_t GetAvailablePhysicalMemory();
// returns an informative general description if the installed and
// available ram on this system. See the GetHostMemoryTotal, and
// Get{Host,Proc}MemoryAvailable methods for more information.
std::string GetMemoryDescription(const char* hostLimitEnvVarName = nullptr,
const char* procLimitEnvVarName = nullptr);
// Retrieve amount of physical memory installed on the system in KiB
// units.
LongLong GetHostMemoryTotal();
// Get total system RAM in units of KiB available colectivley to all
// processes in a process group. An example of a process group
// are the processes comprising an mpi program which is running in
// parallel. The amount of memory reported may differ from the host
// total if a host wide resource limit is applied. Such reource limits
// are reported to us via an application specified environment variable.
LongLong GetHostMemoryAvailable(const char* hostLimitEnvVarName = nullptr);
// Get total system RAM in units of KiB available to this process.
// This may differ from the host available if a per-process resource
// limit is applied. per-process memory limits are applied on unix
// system via rlimit API. Resource limits that are not imposed via
// rlimit API may be reported to us via an application specified
// environment variable.
LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName = nullptr,
const char* procLimitEnvVarName = nullptr);
// Get the system RAM used by all processes on the host, in units of KiB.
LongLong GetHostMemoryUsed();
// Get system RAM used by this process id in units of KiB.
LongLong GetProcMemoryUsed();
// Return the load average of the machine or -0.0 if it cannot
// be determined.
double GetLoadAverage();
// enable/disable stack trace signal handler. In order to
// produce an informative stack trace the application should
// be dynamically linked and compiled with debug symbols.
static void SetStackTraceOnError(int enable);
// format and return the current program stack in a string. In
// order to produce an informative stack trace the application
// should be dynamically linked and compiled with debug symbols.
static std::string GetProgramStack(int firstFrame, int wholePath);
/** Run the different checks */
void RunCPUCheck();
void RunOSCheck();
void RunMemoryCheck();
};
} // namespace @KWSYS_NAMESPACE@
#endif
-4703
View File
@@ -1,4703 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifdef __osf__
# define _OSF_SOURCE
# define _POSIX_C_SOURCE 199506L
# define _XOPEN_SOURCE_EXTENDED
#endif
#if defined(_WIN32) && \
(defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \
defined(__MINGW32__))
# define KWSYS_WINDOWS_DIRS
#else
# if defined(__SUNPRO_CC)
# include <fcntl.h>
# endif
#endif
#include "kwsysPrivate.h"
#include KWSYS_HEADER(RegularExpression.hxx)
#include KWSYS_HEADER(SystemTools.hxx)
#include KWSYS_HEADER(Directory.hxx)
#include KWSYS_HEADER(FStream.hxx)
#include KWSYS_HEADER(Encoding.h)
#include KWSYS_HEADER(Encoding.hxx)
#include <fstream>
#include <iostream>
#include <set>
#include <sstream>
#include <utility>
#include <vector>
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Directory.hxx.in"
# include "Encoding.hxx.in"
# include "FStream.hxx.in"
# include "RegularExpression.hxx.in"
# include "SystemTools.hxx.in"
#endif
#ifdef _MSC_VER
# pragma warning(disable : 4786)
#endif
#if defined(__sgi) && !defined(__GNUC__)
# pragma set woff 1375 /* base class destructor not virtual */
#endif
#include <ctype.h>
#include <errno.h>
#ifdef __QNX__
# include <malloc.h> /* for malloc/free on QNX */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__)
# include <strings.h> /* for strcasecmp */
#endif
#ifdef _MSC_VER
# define umask _umask // Note this is still umask on Borland
#endif
// support for realpath call
#ifndef _WIN32
# include <limits.h>
# include <pwd.h>
# include <sys/ioctl.h>
# include <sys/time.h>
# include <sys/wait.h>
# include <unistd.h>
# include <utime.h>
# ifndef __VMS
# include <sys/param.h>
# include <termios.h>
# endif
# include <signal.h> /* sigprocmask */
#endif
#ifdef __linux
# include <linux/fs.h>
#endif
// Windows API.
#if defined(_WIN32)
# include <windows.h>
# include <winioctl.h>
# ifndef INVALID_FILE_ATTRIBUTES
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
# endif
# if defined(_MSC_VER) && _MSC_VER >= 1800
# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# endif
#elif defined(__CYGWIN__)
# include <windows.h>
# undef _WIN32
#endif
#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
extern char** environ;
#endif
#ifdef __CYGWIN__
# include <sys/cygwin.h>
#endif
// getpwnam doesn't exist on Windows and Cray Xt3/Catamount
// same for TIOCGWINSZ
#if defined(_WIN32) || defined(__LIBCATAMOUNT__) || \
(defined(HAVE_GETPWNAM) && HAVE_GETPWNAM == 0)
# undef HAVE_GETPWNAM
# undef HAVE_TTY_INFO
#else
# define HAVE_GETPWNAM 1
# define HAVE_TTY_INFO 1
#endif
#define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)"
#define VTK_URL_REGEX \
"([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/" \
"(.+)?"
#ifdef _MSC_VER
# include <sys/utime.h>
#else
# include <utime.h>
#endif
// This is a hack to prevent warnings about these functions being
// declared but not referenced.
#if defined(__sgi) && !defined(__GNUC__)
# include <sys/termios.h>
namespace KWSYS_NAMESPACE {
class SystemToolsHack
{
public:
enum
{
Ref1 = sizeof(cfgetospeed(0)),
Ref2 = sizeof(cfgetispeed(0)),
Ref3 = sizeof(tcgetattr(0, 0)),
Ref4 = sizeof(tcsetattr(0, 0, 0)),
Ref5 = sizeof(cfsetospeed(0, 0)),
Ref6 = sizeof(cfsetispeed(0, 0))
};
};
}
#endif
#if defined(_WIN32) && \
(defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \
defined(__MINGW32__))
# include <direct.h>
# include <io.h>
# define _unlink unlink
#endif
/* The maximum length of a file name. */
#if defined(PATH_MAX)
# define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX
#elif defined(MAXPATHLEN)
# define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN
#else
# define KWSYS_SYSTEMTOOLS_MAXPATH 16384
#endif
#if defined(__WATCOMC__)
# include <direct.h>
# define _mkdir mkdir
# define _rmdir rmdir
# define _getcwd getcwd
# define _chdir chdir
#endif
#if defined(__BEOS__) && !defined(__ZETA__)
# include <be/kernel/OS.h>
# include <be/storage/Path.h>
// BeOS 5 doesn't have usleep(), but it has snooze(), which is identical.
static inline void usleep(unsigned int msec)
{
::snooze(msec);
}
// BeOS 5 also doesn't have realpath(), but its C++ API offers something close.
static inline char* realpath(const char* path, char* resolved_path)
{
const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH;
snprintf(resolved_path, maxlen, "%s", path);
BPath normalized(resolved_path, nullptr, true);
const char* resolved = normalized.Path();
if (resolved != nullptr) // nullptr == No such file.
{
if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) {
return resolved_path;
}
}
return nullptr; // something went wrong.
}
#endif
#ifdef _WIN32
static time_t windows_filetime_to_posix_time(const FILETIME& ft)
{
LARGE_INTEGER date;
date.HighPart = ft.dwHighDateTime;
date.LowPart = ft.dwLowDateTime;
// removes the diff between 1970 and 1601
date.QuadPart -= ((LONGLONG)(369 * 365 + 89) * 24 * 3600 * 10000000);
// converts back from 100-nanoseconds to seconds
return date.QuadPart / 10000000;
}
#endif
#ifdef KWSYS_WINDOWS_DIRS
# include <wctype.h>
inline int Mkdir(const std::string& dir)
{
return _wmkdir(
KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str());
}
inline int Rmdir(const std::string& dir)
{
return _wrmdir(
KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str());
}
inline const char* Getcwd(char* buf, unsigned int len)
{
std::vector<wchar_t> w_buf(len);
if (_wgetcwd(&w_buf[0], len)) {
size_t nlen = kwsysEncoding_wcstombs(buf, &w_buf[0], len);
if (nlen == static_cast<size_t>(-1)) {
return 0;
}
if (nlen < len) {
// make sure the drive letter is capital
if (nlen > 1 && buf[1] == ':') {
buf[0] = toupper(buf[0]);
}
return buf;
}
}
return 0;
}
inline int Chdir(const std::string& dir)
{
# if defined(__BORLANDC__)
return chdir(dir.c_str());
# else
return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str());
# endif
}
inline void Realpath(const std::string& path, std::string& resolved_path,
std::string* errorMessage = 0)
{
std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path);
wchar_t* ptemp;
wchar_t fullpath[MAX_PATH];
DWORD bufferLen = GetFullPathNameW(
tmp.c_str(), sizeof(fullpath) / sizeof(fullpath[0]), fullpath, &ptemp);
if (bufferLen < sizeof(fullpath) / sizeof(fullpath[0])) {
resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath);
KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path);
} else if (errorMessage) {
if (bufferLen) {
*errorMessage = "Destination path buffer size too small.";
} else if (unsigned int errorId = GetLastError()) {
LPSTR message = nullptr;
DWORD size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&message, 0, nullptr);
*errorMessage = std::string(message, size);
LocalFree(message);
} else {
*errorMessage = "Unknown error.";
}
resolved_path = "";
} else {
resolved_path = path;
}
}
#else
# include <sys/types.h>
# include <fcntl.h>
# include <unistd.h>
inline int Mkdir(const std::string& dir)
{
return mkdir(dir.c_str(), 00777);
}
inline int Rmdir(const std::string& dir)
{
return rmdir(dir.c_str());
}
inline const char* Getcwd(char* buf, unsigned int len)
{
return getcwd(buf, len);
}
inline int Chdir(const std::string& dir)
{
return chdir(dir.c_str());
}
inline void Realpath(const std::string& path, std::string& resolved_path,
std::string* errorMessage = nullptr)
{
char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH];
errno = 0;
char* ret = realpath(path.c_str(), resolved_name);
if (ret) {
resolved_path = ret;
} else if (errorMessage) {
if (errno) {
*errorMessage = strerror(errno);
} else {
*errorMessage = "Unknown error.";
}
resolved_path = "";
} else {
// if path resolution fails, return what was passed in
resolved_path = path;
}
}
#endif
#if !defined(_WIN32) && defined(__COMO__)
// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE.
extern "C" {
extern FILE* popen(__const char* __command, __const char* __modes) __THROW;
extern int pclose(FILE* __stream) __THROW;
extern char* realpath(__const char* __restrict __name,
char* __restrict __resolved) __THROW;
extern char* strdup(__const char* __s) __THROW;
extern int putenv(char* __string) __THROW;
}
#endif
namespace KWSYS_NAMESPACE {
double SystemTools::GetTime(void)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return (429.4967296 * ft.dwHighDateTime + 0.0000001 * ft.dwLowDateTime -
11644473600.0);
#else
struct timeval t;
gettimeofday(&t, nullptr);
return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec);
#endif
}
/* Type of character storing the environment. */
#if defined(_WIN32)
typedef wchar_t envchar;
#else
typedef char envchar;
#endif
/* Order by environment key only (VAR from VAR=VALUE). */
struct kwsysEnvCompare
{
bool operator()(const envchar* l, const envchar* r) const
{
#if defined(_WIN32)
const wchar_t* leq = wcschr(l, L'=');
const wchar_t* req = wcschr(r, L'=');
size_t llen = leq ? (leq - l) : wcslen(l);
size_t rlen = req ? (req - r) : wcslen(r);
if (llen == rlen) {
return wcsncmp(l, r, llen) < 0;
} else {
return wcscmp(l, r) < 0;
}
#else
const char* leq = strchr(l, '=');
const char* req = strchr(r, '=');
size_t llen = leq ? static_cast<size_t>(leq - l) : strlen(l);
size_t rlen = req ? static_cast<size_t>(req - r) : strlen(r);
if (llen == rlen) {
return strncmp(l, r, llen) < 0;
} else {
return strcmp(l, r) < 0;
}
#endif
}
};
class kwsysEnvSet : public std::set<const envchar*, kwsysEnvCompare>
{
public:
class Free
{
const envchar* Env;
public:
Free(const envchar* env)
: Env(env)
{
}
~Free() { free(const_cast<envchar*>(this->Env)); }
Free(const Free&) = delete;
Free& operator=(const Free&) = delete;
};
const envchar* Release(const envchar* env)
{
const envchar* old = nullptr;
iterator i = this->find(env);
if (i != this->end()) {
old = *i;
this->erase(i);
}
return old;
}
};
#ifdef _WIN32
struct SystemToolsPathCaseCmp
{
bool operator()(std::string const& l, std::string const& r) const
{
# ifdef _MSC_VER
return _stricmp(l.c_str(), r.c_str()) < 0;
# elif defined(__GNUC__)
return strcasecmp(l.c_str(), r.c_str()) < 0;
# else
return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0;
# endif
}
};
#endif
/**
* SystemTools static variables singleton class.
*/
class SystemToolsStatic
{
public:
typedef std::map<std::string, std::string> StringMap;
#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
/**
* Path translation table from dir to refdir
* Each time 'dir' will be found it will be replace by 'refdir'
*/
StringMap TranslationMap;
#endif
#ifdef _WIN32
static std::string GetCasePathName(std::string const& pathIn);
static std::string GetActualCaseForPathCached(std::string const& path);
static const char* GetEnvBuffered(const char* key);
std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap;
std::map<std::string, std::string> EnvMap;
#endif
#ifdef __CYGWIN__
StringMap Cyg2Win32Map;
#endif
/**
* Actual implementation of ReplaceString.
*/
static void ReplaceString(std::string& source, const char* replace,
size_t replaceSize, const std::string& with);
/**
* Actual implementation of FileIsFullPath.
*/
static bool FileIsFullPath(const char*, size_t);
/**
* Find a filename (file or directory) in the system PATH, with
* optional extra paths.
*/
static std::string FindName(
const std::string& name,
const std::vector<std::string>& path = std::vector<std::string>(),
bool no_system_path = false);
};
#ifdef _WIN32
std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
{
std::string casePath;
// First check if the file is relative. We don't fix relative paths since the
// real case depends on the root directory and the given path fragment may
// have meaning elsewhere in the project.
if (!SystemTools::FileIsFullPath(pathIn)) {
// This looks unnecessary, but it allows for the return value optimization
// since all return paths return the same local variable.
casePath = pathIn;
return casePath;
}
std::vector<std::string> path_components;
SystemTools::SplitPath(pathIn, path_components);
// Start with root component.
std::vector<std::string>::size_type idx = 0;
casePath = path_components[idx++];
// make sure drive letter is always upper case
if (casePath.size() > 1 && casePath[1] == ':') {
casePath[0] = toupper(casePath[0]);
}
const char* sep = "";
// If network path, fill casePath with server/share so FindFirstFile
// will work after that. Maybe someday call other APIs to get
// actual case of servers and shares.
if (path_components.size() > 2 && path_components[0] == "//") {
casePath += path_components[idx++];
casePath += "/";
casePath += path_components[idx++];
sep = "/";
}
// Convert case of all components that exist.
bool converting = true;
for (; idx < path_components.size(); idx++) {
casePath += sep;
sep = "/";
if (converting) {
// If path component contains wildcards, we skip matching
// because these filenames are not allowed on windows,
// and we do not want to match a different file.
if (path_components[idx].find('*') != std::string::npos ||
path_components[idx].find('?') != std::string::npos) {
converting = false;
} else {
std::string test_str = casePath;
test_str += path_components[idx];
WIN32_FIND_DATAW findData;
HANDLE hFind =
::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
if (INVALID_HANDLE_VALUE != hFind) {
path_components[idx] = Encoding::ToNarrow(findData.cFileName);
::FindClose(hFind);
} else {
converting = false;
}
}
}
casePath += path_components[idx];
}
return casePath;
}
std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p)
{
// Check to see if actual case has already been called
// for this path, and the result is stored in the PathCaseMap
auto& pcm = SystemTools::Statics->PathCaseMap;
{
auto itr = pcm.find(p);
if (itr != pcm.end()) {
return itr->second;
}
}
std::string casePath = SystemToolsStatic::GetCasePathName(p);
if (casePath.size() <= MAX_PATH) {
pcm[p] = casePath;
}
return casePath;
}
#endif
// adds the elements of the env variable path to the arg passed in
void SystemTools::GetPath(std::vector<std::string>& path, const char* env)
{
size_t const old_size = path.size();
#if defined(_WIN32) && !defined(__CYGWIN__)
const char pathSep = ';';
#else
const char pathSep = ':';
#endif
if (!env) {
env = "PATH";
}
std::string pathEnv;
if (!SystemTools::GetEnv(env, pathEnv)) {
return;
}
// A hack to make the below algorithm work.
if (!pathEnv.empty() && pathEnv.back() != pathSep) {
pathEnv += pathSep;
}
std::string::size_type start = 0;
bool done = false;
while (!done) {
std::string::size_type endpos = pathEnv.find(pathSep, start);
if (endpos != std::string::npos) {
path.push_back(pathEnv.substr(start, endpos - start));
start = endpos + 1;
} else {
done = true;
}
}
for (std::vector<std::string>::iterator i = path.begin() + old_size;
i != path.end(); ++i) {
SystemTools::ConvertToUnixSlashes(*i);
}
}
#if defined(_WIN32)
const char* SystemToolsStatic::GetEnvBuffered(const char* key)
{
std::string env;
if (SystemTools::GetEnv(key, env)) {
std::string& menv = SystemTools::Statics->EnvMap[key];
if (menv != env) {
menv = std::move(env);
}
return menv.c_str();
}
return nullptr;
}
#endif
const char* SystemTools::GetEnv(const char* key)
{
#if defined(_WIN32)
return SystemToolsStatic::GetEnvBuffered(key);
#else
return getenv(key);
#endif
}
const char* SystemTools::GetEnv(const std::string& key)
{
#if defined(_WIN32)
return SystemToolsStatic::GetEnvBuffered(key.c_str());
#else
return getenv(key.c_str());
#endif
}
bool SystemTools::GetEnv(const char* key, std::string& result)
{
#if defined(_WIN32)
const std::wstring wkey = Encoding::ToWide(key);
const wchar_t* wv = _wgetenv(wkey.c_str());
if (wv) {
result = Encoding::ToNarrow(wv);
return true;
}
#else
const char* v = getenv(key);
if (v) {
result = v;
return true;
}
#endif
return false;
}
bool SystemTools::GetEnv(const std::string& key, std::string& result)
{
return SystemTools::GetEnv(key.c_str(), result);
}
bool SystemTools::HasEnv(const char* key)
{
#if defined(_WIN32)
const std::wstring wkey = Encoding::ToWide(key);
const wchar_t* v = _wgetenv(wkey.c_str());
#else
const char* v = getenv(key);
#endif
return v != nullptr;
}
bool SystemTools::HasEnv(const std::string& key)
{
return SystemTools::HasEnv(key.c_str());
}
#if KWSYS_CXX_HAS_UNSETENV
/* unsetenv("A") removes A from the environment.
On older platforms it returns void instead of int. */
static int kwsysUnPutEnv(const std::string& env)
{
size_t pos = env.find('=');
if (pos != std::string::npos) {
std::string name = env.substr(0, pos);
unsetenv(name.c_str());
} else {
unsetenv(env.c_str());
}
return 0;
}
#elif defined(__CYGWIN__) || defined(__GLIBC__)
/* putenv("A") removes A from the environment. It must not put the
memory in the environment because it does not have any "=" syntax. */
static int kwsysUnPutEnv(const std::string& env)
{
int err = 0;
size_t pos = env.find('=');
size_t const len = pos == std::string::npos ? env.size() : pos;
size_t const sz = len + 1;
char local_buf[256];
char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf;
if (!buf) {
return -1;
}
strncpy(buf, env.c_str(), len);
buf[len] = 0;
if (putenv(buf) < 0 && errno != EINVAL) {
err = errno;
}
if (buf != local_buf) {
free(buf);
}
if (err) {
errno = err;
return -1;
}
return 0;
}
#elif defined(_WIN32)
/* putenv("A=") places "A=" in the environment, which is as close to
removal as we can get with the putenv API. We have to leak the
most recent value placed in the environment for each variable name
on program exit in case exit routines access it. */
static kwsysEnvSet kwsysUnPutEnvSet;
static int kwsysUnPutEnv(std::string const& env)
{
std::wstring wEnv = Encoding::ToWide(env);
size_t const pos = wEnv.find('=');
size_t const len = pos == std::string::npos ? wEnv.size() : pos;
wEnv.resize(len + 1, L'=');
wchar_t* newEnv = _wcsdup(wEnv.c_str());
if (!newEnv) {
return -1;
}
kwsysEnvSet::Free oldEnv(kwsysUnPutEnvSet.Release(newEnv));
kwsysUnPutEnvSet.insert(newEnv);
return _wputenv(newEnv);
}
#else
/* Manipulate the "environ" global directly. */
static int kwsysUnPutEnv(const std::string& env)
{
size_t pos = env.find('=');
size_t const len = pos == std::string::npos ? env.size() : pos;
int in = 0;
int out = 0;
while (environ[in]) {
if (strlen(environ[in]) > len && environ[in][len] == '=' &&
strncmp(env.c_str(), environ[in], len) == 0) {
++in;
} else {
environ[out++] = environ[in++];
}
}
while (out < in) {
environ[out++] = 0;
}
return 0;
}
#endif
#if KWSYS_CXX_HAS_SETENV
/* setenv("A", "B", 1) will set A=B in the environment and makes its
own copies of the strings. */
bool SystemTools::PutEnv(const std::string& env)
{
size_t pos = env.find('=');
if (pos != std::string::npos) {
std::string name = env.substr(0, pos);
return setenv(name.c_str(), env.c_str() + pos + 1, 1) == 0;
} else {
return kwsysUnPutEnv(env) == 0;
}
}
bool SystemTools::UnPutEnv(const std::string& env)
{
return kwsysUnPutEnv(env) == 0;
}
#else
/* putenv("A=B") will set A=B in the environment. Most putenv implementations
put their argument directly in the environment. They never free the memory
on program exit. Keep an active set of pointers to memory we allocate and
pass to putenv, one per environment key. At program exit remove any
environment values that may still reference memory we allocated. Then free
the memory. This will not affect any environment values we never set. */
# ifdef __INTEL_COMPILER
# pragma warning disable 444 /* base has non-virtual destructor */
# endif
class kwsysEnv : public kwsysEnvSet
{
public:
~kwsysEnv()
{
for (iterator i = this->begin(); i != this->end(); ++i) {
# if defined(_WIN32)
const std::string s = Encoding::ToNarrow(*i);
kwsysUnPutEnv(s);
# else
kwsysUnPutEnv(*i);
# endif
free(const_cast<envchar*>(*i));
}
}
bool Put(const char* env)
{
# if defined(_WIN32)
const std::wstring wEnv = Encoding::ToWide(env);
wchar_t* newEnv = _wcsdup(wEnv.c_str());
# else
char* newEnv = strdup(env);
# endif
Free oldEnv(this->Release(newEnv));
this->insert(newEnv);
# if defined(_WIN32)
return _wputenv(newEnv) == 0;
# else
return putenv(newEnv) == 0;
# endif
}
bool UnPut(const char* env)
{
# if defined(_WIN32)
const std::wstring wEnv = Encoding::ToWide(env);
Free oldEnv(this->Release(wEnv.c_str()));
# else
Free oldEnv(this->Release(env));
# endif
return kwsysUnPutEnv(env) == 0;
}
};
static kwsysEnv kwsysEnvInstance;
bool SystemTools::PutEnv(const std::string& env)
{
return kwsysEnvInstance.Put(env.c_str());
}
bool SystemTools::UnPutEnv(const std::string& env)
{
return kwsysEnvInstance.UnPut(env.c_str());
}
#endif
const char* SystemTools::GetExecutableExtension()
{
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS)
return ".exe";
#else
return "";
#endif
}
FILE* SystemTools::Fopen(const std::string& file, const char* mode)
{
#ifdef _WIN32
return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(),
Encoding::ToWide(mode).c_str());
#else
return fopen(file.c_str(), mode);
#endif
}
bool SystemTools::MakeDirectory(const char* path, const mode_t* mode)
{
if (!path) {
return false;
}
return SystemTools::MakeDirectory(std::string(path), mode);
}
bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode)
{
if (SystemTools::PathExists(path)) {
return SystemTools::FileIsDirectory(path);
}
if (path.empty()) {
return false;
}
std::string dir = path;
SystemTools::ConvertToUnixSlashes(dir);
std::string::size_type pos = 0;
std::string topdir;
while ((pos = dir.find('/', pos)) != std::string::npos) {
topdir = dir.substr(0, pos);
if (Mkdir(topdir) == 0 && mode != nullptr) {
SystemTools::SetPermissions(topdir, *mode);
}
++pos;
}
topdir = dir;
if (Mkdir(topdir) != 0) {
// There is a bug in the Borland Run time library which makes MKDIR
// return EACCES when it should return EEXISTS
// if it is some other error besides directory exists
// then return false
if ((errno != EEXIST)
#ifdef __BORLANDC__
&& (errno != EACCES)
#endif
) {
return false;
}
} else if (mode != nullptr) {
SystemTools::SetPermissions(topdir, *mode);
}
return true;
}
// replace replace with with as many times as it shows up in source.
// write the result into source.
void SystemTools::ReplaceString(std::string& source,
const std::string& replace,
const std::string& with)
{
// do while hangs if replaceSize is 0
if (replace.empty()) {
return;
}
SystemToolsStatic::ReplaceString(source, replace.c_str(), replace.size(),
with);
}
void SystemTools::ReplaceString(std::string& source, const char* replace,
const char* with)
{
// do while hangs if replaceSize is 0
if (!*replace) {
return;
}
SystemToolsStatic::ReplaceString(source, replace, strlen(replace),
with ? with : "");
}
void SystemToolsStatic::ReplaceString(std::string& source, const char* replace,
size_t replaceSize,
const std::string& with)
{
const char* src = source.c_str();
char* searchPos = const_cast<char*>(strstr(src, replace));
// get out quick if string is not found
if (!searchPos) {
return;
}
// perform replacements until done
char* orig = strdup(src);
char* currentPos = orig;
searchPos = searchPos - src + orig;
// initialize the result
source.erase(source.begin(), source.end());
do {
*searchPos = '\0';
source += currentPos;
currentPos = searchPos + replaceSize;
// replace
source += with;
searchPos = strstr(currentPos, replace);
} while (searchPos);
// copy any trailing text
source += currentPos;
free(orig);
}
#if defined(_WIN32) && !defined(__CYGWIN__)
# 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
static bool SystemToolsParseRegistryKey(const std::string& key,
HKEY& primaryKey, std::string& second,
std::string& valuename)
{
std::string primary = key;
size_t start = primary.find('\\');
if (start == std::string::npos) {
return false;
}
size_t valuenamepos = primary.find(';');
if (valuenamepos != std::string::npos) {
valuename = primary.substr(valuenamepos + 1);
}
second = primary.substr(start + 1, valuenamepos - start - 1);
primary = primary.substr(0, start);
if (primary == "HKEY_CURRENT_USER") {
primaryKey = HKEY_CURRENT_USER;
}
if (primary == "HKEY_CURRENT_CONFIG") {
primaryKey = HKEY_CURRENT_CONFIG;
}
if (primary == "HKEY_CLASSES_ROOT") {
primaryKey = HKEY_CLASSES_ROOT;
}
if (primary == "HKEY_LOCAL_MACHINE") {
primaryKey = HKEY_LOCAL_MACHINE;
}
if (primary == "HKEY_USERS") {
primaryKey = HKEY_USERS;
}
return true;
}
static DWORD SystemToolsMakeRegistryMode(DWORD mode,
SystemTools::KeyWOW64 view)
{
// only add the modes when on a system that supports Wow64.
static FARPROC wow64p =
GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process");
if (wow64p == nullptr) {
return mode;
}
if (view == SystemTools::KeyWOW64_32) {
return mode | KWSYS_ST_KEY_WOW64_32KEY;
} else if (view == SystemTools::KeyWOW64_64) {
return mode | KWSYS_ST_KEY_WOW64_64KEY;
}
return mode;
}
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
bool SystemTools::GetRegistrySubKeys(const std::string& key,
std::vector<std::string>& subkeys,
KeyWOW64 view)
{
HKEY primaryKey = HKEY_CURRENT_USER;
std::string second;
std::string valuename;
if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
return false;
}
HKEY hKey;
if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
SystemToolsMakeRegistryMode(KEY_READ, view),
&hKey) != ERROR_SUCCESS) {
return false;
} else {
wchar_t name[1024];
DWORD dwNameSize = sizeof(name) / sizeof(name[0]);
DWORD i = 0;
while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS) {
subkeys.push_back(Encoding::ToNarrow(name));
++i;
}
RegCloseKey(hKey);
}
return true;
}
#else
bool SystemTools::GetRegistrySubKeys(const std::string&,
std::vector<std::string>&, KeyWOW64)
{
return false;
}
#endif
// Read a registry value.
// Example :
// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
// => will return the data of the "default" value of the key
// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
// => will return the data of the "Root" value of the key
#if defined(_WIN32) && !defined(__CYGWIN__)
bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value,
KeyWOW64 view)
{
bool valueset = false;
HKEY primaryKey = HKEY_CURRENT_USER;
std::string second;
std::string valuename;
if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
return false;
}
HKEY hKey;
if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
SystemToolsMakeRegistryMode(KEY_READ, view),
&hKey) != ERROR_SUCCESS) {
return false;
} else {
DWORD dwType, dwSize;
dwSize = 1023;
wchar_t data[1024];
if (RegQueryValueExW(hKey, Encoding::ToWide(valuename).c_str(), nullptr,
&dwType, (BYTE*)data, &dwSize) == ERROR_SUCCESS) {
if (dwType == REG_SZ) {
value = Encoding::ToNarrow(data);
valueset = true;
} else if (dwType == REG_EXPAND_SZ) {
wchar_t expanded[1024];
DWORD dwExpandedSize = sizeof(expanded) / sizeof(expanded[0]);
if (ExpandEnvironmentStringsW(data, expanded, dwExpandedSize)) {
value = Encoding::ToNarrow(expanded);
valueset = true;
}
}
}
RegCloseKey(hKey);
}
return valueset;
}
#else
bool SystemTools::ReadRegistryValue(const std::string&, std::string&, KeyWOW64)
{
return false;
}
#endif
// Write a registry value.
// Example :
// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
// => will set the data of the "default" value of the key
// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
// => will set the data of the "Root" value of the key
#if defined(_WIN32) && !defined(__CYGWIN__)
bool SystemTools::WriteRegistryValue(const std::string& key,
const std::string& value, KeyWOW64 view)
{
HKEY primaryKey = HKEY_CURRENT_USER;
std::string second;
std::string valuename;
if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
return false;
}
HKEY hKey;
DWORD dwDummy;
wchar_t lpClass[] = L"";
if (RegCreateKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, lpClass,
REG_OPTION_NON_VOLATILE,
SystemToolsMakeRegistryMode(KEY_WRITE, view), nullptr,
&hKey, &dwDummy) != ERROR_SUCCESS) {
return false;
}
std::wstring wvalue = Encoding::ToWide(value);
if (RegSetValueExW(hKey, Encoding::ToWide(valuename).c_str(), 0, REG_SZ,
(CONST BYTE*)wvalue.c_str(),
(DWORD)(sizeof(wchar_t) * (wvalue.size() + 1))) ==
ERROR_SUCCESS) {
return true;
}
return false;
}
#else
bool SystemTools::WriteRegistryValue(const std::string&, const std::string&,
KeyWOW64)
{
return false;
}
#endif
// Delete a registry value.
// Example :
// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
// => will delete the data of the "default" value of the key
// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
// => will delete the data of the "Root" value of the key
#if defined(_WIN32) && !defined(__CYGWIN__)
bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view)
{
HKEY primaryKey = HKEY_CURRENT_USER;
std::string second;
std::string valuename;
if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
return false;
}
HKEY hKey;
if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
SystemToolsMakeRegistryMode(KEY_WRITE, view),
&hKey) != ERROR_SUCCESS) {
return false;
} else {
if (RegDeleteValue(hKey, (LPTSTR)valuename.c_str()) == ERROR_SUCCESS) {
RegCloseKey(hKey);
return true;
}
}
return false;
}
#else
bool SystemTools::DeleteRegistryValue(const std::string&, KeyWOW64)
{
return false;
}
#endif
bool SystemTools::SameFile(const std::string& file1, const std::string& file2)
{
#ifdef _WIN32
HANDLE hFile1, hFile2;
hFile1 =
CreateFileW(Encoding::ToWide(file1).c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
hFile2 =
CreateFileW(Encoding::ToWide(file2).c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (hFile1 == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE) {
if (hFile1 != INVALID_HANDLE_VALUE) {
CloseHandle(hFile1);
}
if (hFile2 != INVALID_HANDLE_VALUE) {
CloseHandle(hFile2);
}
return false;
}
BY_HANDLE_FILE_INFORMATION fiBuf1;
BY_HANDLE_FILE_INFORMATION fiBuf2;
GetFileInformationByHandle(hFile1, &fiBuf1);
GetFileInformationByHandle(hFile2, &fiBuf2);
CloseHandle(hFile1);
CloseHandle(hFile2);
return (fiBuf1.dwVolumeSerialNumber == fiBuf2.dwVolumeSerialNumber &&
fiBuf1.nFileIndexHigh == fiBuf2.nFileIndexHigh &&
fiBuf1.nFileIndexLow == fiBuf2.nFileIndexLow);
#else
struct stat fileStat1, fileStat2;
if (stat(file1.c_str(), &fileStat1) == 0 &&
stat(file2.c_str(), &fileStat2) == 0) {
// see if the files are the same file
// check the device inode and size
if (memcmp(&fileStat2.st_dev, &fileStat1.st_dev,
sizeof(fileStat1.st_dev)) == 0 &&
memcmp(&fileStat2.st_ino, &fileStat1.st_ino,
sizeof(fileStat1.st_ino)) == 0 &&
fileStat2.st_size == fileStat1.st_size) {
return true;
}
}
return false;
#endif
}
bool SystemTools::PathExists(const std::string& path)
{
if (path.empty()) {
return false;
}
#if defined(__CYGWIN__)
// Convert path to native windows path if possible.
char winpath[MAX_PATH];
if (SystemTools::PathCygwinToWin32(path.c_str(), winpath)) {
return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES);
}
struct stat st;
return lstat(path.c_str(), &st) == 0;
#elif defined(_WIN32)
return (GetFileAttributesW(Encoding::ToWindowsExtendedPath(path).c_str()) !=
INVALID_FILE_ATTRIBUTES);
#else
struct stat st;
return lstat(path.c_str(), &st) == 0;
#endif
}
bool SystemTools::FileExists(const char* filename)
{
if (!filename) {
return false;
}
return SystemTools::FileExists(std::string(filename));
}
bool SystemTools::FileExists(const std::string& filename)
{
if (filename.empty()) {
return false;
}
#if defined(__CYGWIN__)
// Convert filename to native windows path if possible.
char winpath[MAX_PATH];
if (SystemTools::PathCygwinToWin32(filename.c_str(), winpath)) {
return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES);
}
return access(filename.c_str(), R_OK) == 0;
#elif defined(_WIN32)
DWORD attr =
GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str());
if (attr == INVALID_FILE_ATTRIBUTES) {
return false;
}
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
// Using 0 instead of GENERIC_READ as it allows reading of file attributes
// even if we do not have permission to read the file itself
HANDLE handle =
CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), 0, 0,
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (handle == INVALID_HANDLE_VALUE) {
return false;
}
CloseHandle(handle);
}
return true;
#else
// SCO OpenServer 5.0.7/3.2's command has 711 permission.
# if defined(_SCO_DS)
return access(filename.c_str(), F_OK) == 0;
# else
return access(filename.c_str(), R_OK) == 0;
# endif
#endif
}
bool SystemTools::FileExists(const char* filename, bool isFile)
{
if (!filename) {
return false;
}
return SystemTools::FileExists(std::string(filename), isFile);
}
bool SystemTools::FileExists(const std::string& filename, bool isFile)
{
if (SystemTools::FileExists(filename)) {
// If isFile is set return not FileIsDirectory,
// so this will only be true if it is a file
return !isFile || !SystemTools::FileIsDirectory(filename);
}
return false;
}
bool SystemTools::TestFileAccess(const char* filename,
TestFilePermissions permissions)
{
if (!filename) {
return false;
}
return SystemTools::TestFileAccess(std::string(filename), permissions);
}
bool SystemTools::TestFileAccess(const std::string& filename,
TestFilePermissions permissions)
{
if (filename.empty()) {
return false;
}
#if defined(_WIN32) && !defined(__CYGWIN__)
// If execute set, change to read permission (all files on Windows
// are executable if they are readable). The CRT will always fail
// if you pass an execute bit.
if (permissions & TEST_FILE_EXECUTE) {
permissions &= ~TEST_FILE_EXECUTE;
permissions |= TEST_FILE_READ;
}
return _waccess(Encoding::ToWindowsExtendedPath(filename).c_str(),
permissions) == 0;
#else
return access(filename.c_str(), permissions) == 0;
#endif
}
int SystemTools::Stat(const char* path, SystemTools::Stat_t* buf)
{
if (!path) {
errno = EFAULT;
return -1;
}
return SystemTools::Stat(std::string(path), buf);
}
int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf)
{
if (path.empty()) {
errno = ENOENT;
return -1;
}
#if defined(_WIN32) && !defined(__CYGWIN__)
// Ideally we should use Encoding::ToWindowsExtendedPath to support
// long paths, but _wstat64 rejects paths with '?' in them, thinking
// they are wildcards.
std::wstring const& wpath = Encoding::ToWide(path);
# if defined(__BORLANDC__)
return _wstati64(wpath.c_str(), buf);
# else
return _wstat64(wpath.c_str(), buf);
# endif
#else
return stat(path.c_str(), buf);
#endif
}
#ifdef __CYGWIN__
bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path)
{
auto itr = SystemTools::Statics->Cyg2Win32Map.find(path);
if (itr != SystemTools::Statics->Cyg2Win32Map.end()) {
strncpy(win32_path, itr->second.c_str(), MAX_PATH);
} else {
if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) !=
0) {
win32_path[0] = 0;
}
SystemTools::Statics->Cyg2Win32Map.insert(
SystemToolsStatic::StringMap::value_type(path, win32_path));
}
return win32_path[0] != 0;
}
#endif
bool SystemTools::Touch(const std::string& filename, bool create)
{
if (!SystemTools::PathExists(filename)) {
if (create) {
FILE* file = Fopen(filename, "a+b");
if (file) {
fclose(file);
return true;
}
return false;
} else {
return true;
}
}
#if defined(_WIN32) && !defined(__CYGWIN__)
HANDLE h = CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(),
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (!h) {
return false;
}
FILETIME mtime;
GetSystemTimeAsFileTime(&mtime);
if (!SetFileTime(h, 0, 0, &mtime)) {
CloseHandle(h);
return false;
}
CloseHandle(h);
#elif KWSYS_CXX_HAS_UTIMENSAT
// utimensat is only available on newer Unixes and macOS 10.13+
if (utimensat(AT_FDCWD, filename.c_str(), nullptr, 0) < 0) {
return false;
}
#else
// fall back to utimes
if (utimes(filename.c_str(), nullptr) < 0) {
return false;
}
#endif
return true;
}
bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2,
int* result)
{
// Default to same time.
*result = 0;
#if !defined(_WIN32) || defined(__CYGWIN__)
// POSIX version. Use stat function to get file modification time.
struct stat s1;
if (stat(f1.c_str(), &s1) != 0) {
return false;
}
struct stat s2;
if (stat(f2.c_str(), &s2) != 0) {
return false;
}
# if KWSYS_CXX_STAT_HAS_ST_MTIM
// Compare using nanosecond resolution.
if (s1.st_mtim.tv_sec < s2.st_mtim.tv_sec) {
*result = -1;
} else if (s1.st_mtim.tv_sec > s2.st_mtim.tv_sec) {
*result = 1;
} else if (s1.st_mtim.tv_nsec < s2.st_mtim.tv_nsec) {
*result = -1;
} else if (s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec) {
*result = 1;
}
# elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
// Compare using nanosecond resolution.
if (s1.st_mtimespec.tv_sec < s2.st_mtimespec.tv_sec) {
*result = -1;
} else if (s1.st_mtimespec.tv_sec > s2.st_mtimespec.tv_sec) {
*result = 1;
} else if (s1.st_mtimespec.tv_nsec < s2.st_mtimespec.tv_nsec) {
*result = -1;
} else if (s1.st_mtimespec.tv_nsec > s2.st_mtimespec.tv_nsec) {
*result = 1;
}
# else
// Compare using 1 second resolution.
if (s1.st_mtime < s2.st_mtime) {
*result = -1;
} else if (s1.st_mtime > s2.st_mtime) {
*result = 1;
}
# endif
#else
// Windows version. Get the modification time from extended file attributes.
WIN32_FILE_ATTRIBUTE_DATA f1d;
WIN32_FILE_ATTRIBUTE_DATA f2d;
if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f1).c_str(),
GetFileExInfoStandard, &f1d)) {
return false;
}
if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f2).c_str(),
GetFileExInfoStandard, &f2d)) {
return false;
}
// Compare the file times using resolution provided by system call.
*result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime);
#endif
return true;
}
// Return a capitalized string (i.e the first letter is uppercased, all other
// are lowercased)
std::string SystemTools::Capitalized(const std::string& s)
{
std::string n;
if (s.empty()) {
return n;
}
n.resize(s.size());
n[0] = static_cast<std::string::value_type>(toupper(s[0]));
for (size_t i = 1; i < s.size(); i++) {
n[i] = static_cast<std::string::value_type>(tolower(s[i]));
}
return n;
}
// Return capitalized words
std::string SystemTools::CapitalizedWords(const std::string& s)
{
std::string n(s);
for (size_t i = 0; i < s.size(); i++) {
#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG)
// MS has an assert that will fail if s[i] < 0; setting
// LC_CTYPE using setlocale() does *not* help. Painful.
if ((int)s[i] >= 0 && isalpha(s[i]) &&
(i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1]))))
#else
if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1])))
#endif
{
n[i] = static_cast<std::string::value_type>(toupper(s[i]));
}
}
return n;
}
// Return uncapitalized words
std::string SystemTools::UnCapitalizedWords(const std::string& s)
{
std::string n(s);
for (size_t i = 0; i < s.size(); i++) {
#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG)
// MS has an assert that will fail if s[i] < 0; setting
// LC_CTYPE using setlocale() does *not* help. Painful.
if ((int)s[i] >= 0 && isalpha(s[i]) &&
(i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1]))))
#else
if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1])))
#endif
{
n[i] = static_cast<std::string::value_type>(tolower(s[i]));
}
}
return n;
}
// only works for words with at least two letters
std::string SystemTools::AddSpaceBetweenCapitalizedWords(const std::string& s)
{
std::string n;
if (!s.empty()) {
n.reserve(s.size());
n += s[0];
for (size_t i = 1; i < s.size(); i++) {
if (isupper(s[i]) && !isspace(s[i - 1]) && !isupper(s[i - 1])) {
n += ' ';
}
n += s[i];
}
}
return n;
}
char* SystemTools::AppendStrings(const char* str1, const char* str2)
{
if (!str1) {
return SystemTools::DuplicateString(str2);
}
if (!str2) {
return SystemTools::DuplicateString(str1);
}
size_t len1 = strlen(str1);
char* newstr = new char[len1 + strlen(str2) + 1];
if (!newstr) {
return nullptr;
}
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 nullptr;
}
strcpy(newstr, str1);
strcat(newstr + len1, str2);
strcat(newstr + len1 + len2, str3);
return newstr;
}
// Return a lower case string
std::string SystemTools::LowerCase(const std::string& s)
{
std::string n;
n.resize(s.size());
for (size_t i = 0; i < s.size(); i++) {
n[i] = static_cast<std::string::value_type>(tolower(s[i]));
}
return n;
}
// Return a lower case string
std::string SystemTools::UpperCase(const std::string& s)
{
std::string n;
n.resize(s.size());
for (size_t i = 0; i < s.size(); i++) {
n[i] = static_cast<std::string::value_type>(toupper(s[i]));
}
return n;
}
// Count char in string
size_t SystemTools::CountChar(const char* str, char c)
{
size_t count = 0;
if (str) {
while (*str) {
if (*str == c) {
++count;
}
++str;
}
}
return count;
}
// Remove chars in string
char* SystemTools::RemoveChars(const char* str, const char* toremove)
{
if (!str) {
return nullptr;
}
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 nullptr;
}
char* clean_str = new char[strlen(str) + 1];
char* ptr = clean_str;
while (*str) {
if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'F')) {
*ptr++ = *str;
}
++str;
}
*ptr = '\0';
return clean_str;
}
// Replace chars in string
char* SystemTools::ReplaceChars(char* str, const char* toreplace,
char replacement)
{
if (str) {
char* ptr = str;
while (*ptr) {
const char* ptr2 = toreplace;
while (*ptr2) {
if (*ptr == *ptr2) {
*ptr = replacement;
}
++ptr2;
}
++ptr;
}
}
return str;
}
// Returns if string starts with another string
bool SystemTools::StringStartsWith(const char* str1, const char* str2)
{
if (!str1 || !str2) {
return false;
}
size_t len1 = strlen(str1), len2 = strlen(str2);
return len1 >= len2 && !strncmp(str1, str2, len2) ? true : false;
}
// Returns if string starts with another string
bool SystemTools::StringStartsWith(const std::string& str1, const char* str2)
{
if (!str2) {
return false;
}
size_t len1 = str1.size(), len2 = strlen(str2);
return len1 >= len2 && !strncmp(str1.c_str(), str2, len2) ? true : false;
}
// Returns if string ends with another string
bool SystemTools::StringEndsWith(const char* str1, const char* str2)
{
if (!str1 || !str2) {
return false;
}
size_t len1 = strlen(str1), len2 = strlen(str2);
return len1 >= len2 && !strncmp(str1 + (len1 - len2), str2, len2) ? true
: false;
}
// Returns if string ends with another string
bool SystemTools::StringEndsWith(const std::string& str1, const char* str2)
{
if (!str2) {
return false;
}
size_t len1 = str1.size(), len2 = strlen(str2);
return len1 >= len2 && !strncmp(str1.c_str() + (len1 - len2), str2, len2)
? true
: false;
}
// Returns a pointer to the last occurrence of str2 in str1
const char* SystemTools::FindLastString(const char* str1, const char* str2)
{
if (!str1 || !str2) {
return nullptr;
}
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 nullptr;
}
// Duplicate string
char* SystemTools::DuplicateString(const char* str)
{
if (str) {
char* newstr = new char[strlen(str) + 1];
return strcpy(newstr, str);
}
return nullptr;
}
// Return a cropped string
std::string SystemTools::CropString(const std::string& s, size_t max_len)
{
if (!s.size() || max_len == 0 || max_len >= s.size()) {
return s;
}
std::string n;
n.reserve(max_len);
size_t middle = max_len / 2;
n += s.substr(0, middle);
n += s.substr(s.size() - (max_len - middle));
if (max_len > 2) {
n[middle] = '.';
if (max_len > 3) {
n[middle - 1] = '.';
if (max_len > 4) {
n[middle + 1] = '.';
}
}
}
return n;
}
std::vector<std::string> SystemTools::SplitString(const std::string& p,
char sep, bool isPath)
{
std::string path = p;
std::vector<std::string> paths;
if (path.empty()) {
return paths;
}
if (isPath && path[0] == '/') {
path.erase(path.begin());
paths.push_back("/");
}
std::string::size_type pos1 = 0;
std::string::size_type pos2 = path.find(sep, pos1 + 1);
while (pos2 != std::string::npos) {
paths.push_back(path.substr(pos1, pos2 - pos1));
pos1 = pos2 + 1;
pos2 = path.find(sep, pos1 + 1);
}
paths.push_back(path.substr(pos1, pos2 - pos1));
return paths;
}
int SystemTools::EstimateFormatLength(const char* format, va_list ap)
{
if (!format) {
return 0;
}
// Quick-hack attempt at estimating the length of the string.
// Should never under-estimate.
// Start with the length of the format string itself.
size_t length = strlen(format);
// Increase the length for every argument in the format.
const char* cur = format;
while (*cur) {
if (*cur++ == '%') {
// Skip "%%" since it doesn't correspond to a va_arg.
if (*cur != '%') {
while (!int(isalpha(*cur))) {
++cur;
}
switch (*cur) {
case 's': {
// Check the length of the string.
char* s = va_arg(ap, char*);
if (s) {
length += strlen(s);
}
} break;
case 'e':
case 'f':
case 'g': {
// Assume the argument contributes no more than 64 characters.
length += 64;
// Eat the argument.
static_cast<void>(va_arg(ap, double));
} break;
default: {
// Assume the argument contributes no more than 64 characters.
length += 64;
// Eat the argument.
static_cast<void>(va_arg(ap, int));
} break;
}
}
// Move past the characters just tested.
++cur;
}
}
return static_cast<int>(length);
}
std::string SystemTools::EscapeChars(const char* str,
const char* chars_to_escape,
char escape_char)
{
std::string n;
if (str) {
if (!chars_to_escape || !*chars_to_escape) {
n.append(str);
} else {
n.reserve(strlen(str));
while (*str) {
const char* ptr = chars_to_escape;
while (*ptr) {
if (*str == *ptr) {
n += escape_char;
break;
}
++ptr;
}
n += *str;
++str;
}
}
}
return n;
}
#ifdef __VMS
static void ConvertVMSToUnix(std::string& path)
{
std::string::size_type rootEnd = path.find(":[");
std::string::size_type pathEnd = path.find("]");
if (rootEnd != std::string::npos) {
std::string root = path.substr(0, rootEnd);
std::string pathPart = path.substr(rootEnd + 2, pathEnd - rootEnd - 2);
const char* pathCString = pathPart.c_str();
const char* pos0 = pathCString;
for (std::string::size_type pos = 0; *pos0; ++pos) {
if (*pos0 == '.') {
pathPart[pos] = '/';
}
pos0++;
}
path = "/" + root + "/" + pathPart;
}
}
#endif
// convert windows slashes to unix slashes
void SystemTools::ConvertToUnixSlashes(std::string& path)
{
if (path.empty()) {
return;
}
const char* pathCString = path.c_str();
bool hasDoubleSlash = false;
#ifdef __VMS
ConvertVMSToUnix(path);
#else
const char* pos0 = pathCString;
for (std::string::size_type pos = 0; *pos0; ++pos) {
if (*pos0 == '\\') {
path[pos] = '/';
}
// Also, reuse the loop to check for slash followed by another slash
if (!hasDoubleSlash && *(pos0 + 1) == '/' && *(pos0 + 2) == '/') {
# 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++;
}
if (hasDoubleSlash) {
SystemTools::ReplaceString(path, "//", "/");
}
#endif
// remove any trailing slash
// if there is a tilda ~ then replace it with HOME
pathCString = path.c_str();
if (pathCString[0] == '~' &&
(pathCString[1] == '/' || pathCString[1] == '\0')) {
std::string homeEnv;
if (SystemTools::GetEnv("HOME", homeEnv)) {
path.replace(0, 1, homeEnv);
}
}
#ifdef HAVE_GETPWNAM
else if (pathCString[0] == '~') {
std::string::size_type idx = path.find_first_of("/\0");
std::string user = path.substr(1, idx - 1);
passwd* pw = getpwnam(user.c_str());
if (pw) {
path.replace(0, idx, pw->pw_dir);
}
}
#endif
// remove trailing slash if the path is more than
// a single /
pathCString = path.c_str();
size_t size = path.size();
if (size > 1 && path.back() == '/') {
// if it is c:/ then do not remove the trailing slash
if (!((size == 3 && pathCString[1] == ':'))) {
path.resize(size - 1);
}
}
}
#ifdef _WIN32
std::wstring SystemTools::ConvertToWindowsExtendedPath(
const std::string& source)
{
return Encoding::ToWindowsExtendedPath(source);
}
#endif
// change // to /, and escape any spaces in the path
std::string SystemTools::ConvertToUnixOutputPath(const std::string& path)
{
std::string ret = path;
// remove // except at the beginning might be a cygwin drive
std::string::size_type pos = 1;
while ((pos = ret.find("//", pos)) != std::string::npos) {
ret.erase(pos, 1);
}
// escape spaces and () in the path
if (ret.find_first_of(" ") != std::string::npos) {
std::string result;
char lastch = 1;
for (const char* ch = ret.c_str(); *ch != '\0'; ++ch) {
// if it is already escaped then don't try to escape it again
if ((*ch == ' ') && lastch != '\\') {
result += '\\';
}
result += *ch;
lastch = *ch;
}
ret = result;
}
return ret;
}
std::string SystemTools::ConvertToOutputPath(const std::string& path)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
return SystemTools::ConvertToWindowsOutputPath(path);
#else
return SystemTools::ConvertToUnixOutputPath(path);
#endif
}
// remove double slashes not at the start
std::string SystemTools::ConvertToWindowsOutputPath(const std::string& path)
{
std::string ret;
// make it big enough for all of path and double quotes
ret.reserve(path.size() + 3);
// put path into the string
ret = path;
std::string::size_type pos = 0;
// first convert all of the slashes
while ((pos = ret.find('/', pos)) != std::string::npos) {
ret[pos] = '\\';
pos++;
}
// check for really small paths
if (ret.size() < 2) {
return ret;
}
// now clean up a bit and remove double slashes
// Only if it is not the first position in the path which is a network
// path on windows
pos = 1; // start at position 1
if (ret[0] == '\"') {
pos = 2; // if the string is already quoted then start at 2
if (ret.size() < 3) {
return ret;
}
}
while ((pos = ret.find("\\\\", pos)) != std::string::npos) {
ret.erase(pos, 1);
}
// now double quote the path if it has spaces in it
// and is not already double quoted
if (ret.find(' ') != std::string::npos && ret[0] != '\"') {
ret.insert(static_cast<std::string::size_type>(0),
static_cast<std::string::size_type>(1), '\"');
ret.append(1, '\"');
}
return ret;
}
/**
* Append the filename from the path source to the directory name dir.
*/
static std::string FileInDir(const std::string& source, const std::string& dir)
{
std::string new_destination = dir;
SystemTools::ConvertToUnixSlashes(new_destination);
return new_destination + '/' + SystemTools::GetFilenameName(source);
}
bool SystemTools::CopyFileIfDifferent(const std::string& source,
const std::string& destination)
{
// special check for a destination that is a directory
// FilesDiffer does not handle file to directory compare
if (SystemTools::FileIsDirectory(destination)) {
const std::string new_destination = FileInDir(source, destination);
return SystemTools::CopyFileIfDifferent(source, new_destination);
}
// source and destination are files so do a copy if they
// are different
if (SystemTools::FilesDiffer(source, destination)) {
return SystemTools::CopyFileAlways(source, destination);
}
// at this point the files must be the same so return true
return true;
}
#define KWSYS_ST_BUFFER 4096
bool SystemTools::FilesDiffer(const std::string& source,
const std::string& destination)
{
#if defined(_WIN32)
WIN32_FILE_ATTRIBUTE_DATA statSource;
if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(source).c_str(),
GetFileExInfoStandard, &statSource) == 0) {
return true;
}
WIN32_FILE_ATTRIBUTE_DATA statDestination;
if (GetFileAttributesExW(
Encoding::ToWindowsExtendedPath(destination).c_str(),
GetFileExInfoStandard, &statDestination) == 0) {
return true;
}
if (statSource.nFileSizeHigh != statDestination.nFileSizeHigh ||
statSource.nFileSizeLow != statDestination.nFileSizeLow) {
return true;
}
if (statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0) {
return false;
}
off_t nleft =
((__int64)statSource.nFileSizeHigh << 32) + statSource.nFileSizeLow;
#else
struct stat statSource;
if (stat(source.c_str(), &statSource) != 0) {
return true;
}
struct stat statDestination;
if (stat(destination.c_str(), &statDestination) != 0) {
return true;
}
if (statSource.st_size != statDestination.st_size) {
return true;
}
if (statSource.st_size == 0) {
return false;
}
off_t nleft = statSource.st_size;
#endif
#if defined(_WIN32)
kwsys::ifstream finSource(source.c_str(), (std::ios::binary | std::ios::in));
kwsys::ifstream finDestination(destination.c_str(),
(std::ios::binary | std::ios::in));
#else
kwsys::ifstream finSource(source.c_str());
kwsys::ifstream finDestination(destination.c_str());
#endif
if (!finSource || !finDestination) {
return true;
}
// Compare the files a block at a time.
char source_buf[KWSYS_ST_BUFFER];
char dest_buf[KWSYS_ST_BUFFER];
while (nleft > 0) {
// Read a block from each file.
std::streamsize nnext = (nleft > KWSYS_ST_BUFFER)
? KWSYS_ST_BUFFER
: static_cast<std::streamsize>(nleft);
finSource.read(source_buf, nnext);
finDestination.read(dest_buf, nnext);
// If either failed to read assume they are different.
if (static_cast<std::streamsize>(finSource.gcount()) != nnext ||
static_cast<std::streamsize>(finDestination.gcount()) != nnext) {
return true;
}
// If this block differs the file differs.
if (memcmp(static_cast<const void*>(source_buf),
static_cast<const void*>(dest_buf),
static_cast<size_t>(nnext)) != 0) {
return true;
}
// Update the byte count remaining.
nleft -= nnext;
}
// No differences found.
return false;
}
bool SystemTools::TextFilesDiffer(const std::string& path1,
const std::string& path2)
{
kwsys::ifstream if1(path1.c_str());
kwsys::ifstream if2(path2.c_str());
if (!if1 || !if2) {
return true;
}
for (;;) {
std::string line1, line2;
bool hasData1 = GetLineFromStream(if1, line1);
bool hasData2 = GetLineFromStream(if2, line2);
if (hasData1 != hasData2) {
return true;
}
if (!hasData1) {
break;
}
if (line1 != line2) {
return true;
}
}
return false;
}
/**
* Blockwise copy source to destination file
*/
static bool CopyFileContentBlockwise(const std::string& source,
const std::string& destination)
{
// Open files
#if defined(_WIN32)
kwsys::ifstream fin(
Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)).c_str(),
std::ios::in | std::ios::binary);
#else
kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary);
#endif
if (!fin) {
return false;
}
// try and remove the destination file so that read only destination files
// can be written to.
// If the remove fails continue so that files in read only directories
// that do not allow file removal can be modified.
SystemTools::RemoveFile(destination);
#if defined(_WIN32)
kwsys::ofstream fout(
Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(destination)).c_str(),
std::ios::out | std::ios::trunc | std::ios::binary);
#else
kwsys::ofstream fout(destination.c_str(),
std::ios::out | std::ios::trunc | std::ios::binary);
#endif
if (!fout) {
return false;
}
// This copy loop is very sensitive on certain platforms with
// slightly broken stream libraries (like HPUX). Normally, it is
// incorrect to not check the error condition on the fin.read()
// before using the data, but the fin.gcount() will be zero if an
// error occurred. Therefore, the loop should be safe everywhere.
while (fin) {
const int bufferSize = 4096;
char buffer[bufferSize];
fin.read(buffer, bufferSize);
if (fin.gcount()) {
fout.write(buffer, fin.gcount());
} else {
break;
}
}
// Make sure the operating system has finished writing the file
// before closing it. This will ensure the file is finished before
// the check below.
fout.flush();
fin.close();
fout.close();
if (!fout) {
return false;
}
return true;
}
/**
* Clone the source file to the destination file
*
* If available, the Linux FICLONE ioctl is used to create a check
* copy-on-write clone of the source file.
*
* The method returns false for the following cases:
* - The code has not been compiled on Linux or the ioctl was unknown
* - The source and destination is on different file systems
* - The underlying filesystem does not support file cloning
* - An unspecified error occurred
*/
static bool CloneFileContent(const std::string& source,
const std::string& destination)
{
#if defined(__linux) && defined(FICLONE)
int in = open(source.c_str(), O_RDONLY);
if (in < 0) {
return false;
}
SystemTools::RemoveFile(destination);
int out =
open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (out < 0) {
close(in);
return false;
}
int result = ioctl(out, FICLONE, in);
close(in);
close(out);
if (result < 0) {
return false;
}
return true;
#else
(void)source;
(void)destination;
return false;
#endif
}
/**
* Copy a file named by "source" to the file named by "destination".
*/
bool SystemTools::CopyFileAlways(const std::string& source,
const std::string& destination)
{
mode_t perm = 0;
bool perms = SystemTools::GetPermissions(source, perm);
std::string real_destination = destination;
if (SystemTools::FileIsDirectory(source)) {
SystemTools::MakeDirectory(destination);
} else {
// If destination is a directory, try to create a file with the same
// name as the source in that directory.
std::string destination_dir;
if (SystemTools::FileIsDirectory(destination)) {
destination_dir = real_destination;
SystemTools::ConvertToUnixSlashes(real_destination);
real_destination += '/';
std::string source_name = source;
real_destination += SystemTools::GetFilenameName(source_name);
} else {
destination_dir = SystemTools::GetFilenamePath(destination);
}
// If files are the same do not copy
if (SystemTools::SameFile(source, real_destination)) {
return true;
}
// Create destination directory
SystemTools::MakeDirectory(destination_dir);
if (!CloneFileContent(source, real_destination)) {
// if cloning did not succeed, fall back to blockwise copy
if (!CopyFileContentBlockwise(source, real_destination)) {
return false;
}
}
}
if (perms) {
if (!SystemTools::SetPermissions(real_destination, perm)) {
return false;
}
}
return true;
}
bool SystemTools::CopyAFile(const std::string& source,
const std::string& destination, bool always)
{
if (always) {
return SystemTools::CopyFileAlways(source, destination);
} else {
return SystemTools::CopyFileIfDifferent(source, destination);
}
}
/**
* Copy a directory content from "source" directory to the directory named by
* "destination".
*/
bool SystemTools::CopyADirectory(const std::string& source,
const std::string& destination, bool always)
{
Directory dir;
if (dir.Load(source) == 0) {
return false;
}
size_t fileNum;
if (!SystemTools::MakeDirectory(destination)) {
return false;
}
for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") &&
strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) {
std::string fullPath = source;
fullPath += "/";
fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
if (SystemTools::FileIsDirectory(fullPath)) {
std::string fullDestPath = destination;
fullDestPath += "/";
fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum));
if (!SystemTools::CopyADirectory(fullPath, fullDestPath, always)) {
return false;
}
} else {
if (!SystemTools::CopyAFile(fullPath, destination, always)) {
return false;
}
}
}
}
return true;
}
// return size of file; also returns zero if no file exists
unsigned long SystemTools::FileLength(const std::string& filename)
{
unsigned long length = 0;
#ifdef _WIN32
WIN32_FILE_ATTRIBUTE_DATA fs;
if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(),
GetFileExInfoStandard, &fs) != 0) {
/* To support the full 64-bit file size, use fs.nFileSizeHigh
* and fs.nFileSizeLow to construct the 64 bit size
length = ((__int64)fs.nFileSizeHigh << 32) + fs.nFileSizeLow;
*/
length = static_cast<unsigned long>(fs.nFileSizeLow);
}
#else
struct stat fs;
if (stat(filename.c_str(), &fs) == 0) {
length = static_cast<unsigned long>(fs.st_size);
}
#endif
return length;
}
int SystemTools::Strucmp(const char* l, const char* r)
{
int lc;
int rc;
do {
lc = tolower(*l++);
rc = tolower(*r++);
} while (lc == rc && lc);
return lc - rc;
}
// return file's modified time
long int SystemTools::ModifiedTime(const std::string& filename)
{
long int mt = 0;
#ifdef _WIN32
WIN32_FILE_ATTRIBUTE_DATA fs;
if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(),
GetFileExInfoStandard, &fs) != 0) {
mt = windows_filetime_to_posix_time(fs.ftLastWriteTime);
}
#else
struct stat fs;
if (stat(filename.c_str(), &fs) == 0) {
mt = static_cast<long int>(fs.st_mtime);
}
#endif
return mt;
}
// return file's creation time
long int SystemTools::CreationTime(const std::string& filename)
{
long int ct = 0;
#ifdef _WIN32
WIN32_FILE_ATTRIBUTE_DATA fs;
if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(),
GetFileExInfoStandard, &fs) != 0) {
ct = windows_filetime_to_posix_time(fs.ftCreationTime);
}
#else
struct stat fs;
if (stat(filename.c_str(), &fs) == 0) {
ct = fs.st_ctime >= 0 ? static_cast<long int>(fs.st_ctime) : 0;
}
#endif
return ct;
}
std::string SystemTools::GetLastSystemError()
{
int e = errno;
return strerror(e);
}
bool SystemTools::RemoveFile(const std::string& source)
{
#ifdef _WIN32
std::wstring const& ws = Encoding::ToWindowsExtendedPath(source);
if (DeleteFileW(ws.c_str())) {
return true;
}
DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
return true;
}
if (err != ERROR_ACCESS_DENIED) {
return false;
}
/* The file may be read-only. Try adding write permission. */
mode_t mode;
if (!SystemTools::GetPermissions(source, mode) ||
!SystemTools::SetPermissions(source, S_IWRITE)) {
SetLastError(err);
return false;
}
const DWORD DIRECTORY_SOFT_LINK_ATTRS =
FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
DWORD attrs = GetFileAttributesW(ws.c_str());
if (attrs != INVALID_FILE_ATTRIBUTES &&
(attrs & DIRECTORY_SOFT_LINK_ATTRS) == DIRECTORY_SOFT_LINK_ATTRS &&
RemoveDirectoryW(ws.c_str())) {
return true;
}
if (DeleteFileW(ws.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND ||
GetLastError() == ERROR_PATH_NOT_FOUND) {
return true;
}
/* Try to restore the original permissions. */
SystemTools::SetPermissions(source, mode);
SetLastError(err);
return false;
#else
return unlink(source.c_str()) == 0 || errno == ENOENT;
#endif
}
bool SystemTools::RemoveADirectory(const std::string& source)
{
// Add write permission to the directory so we can modify its
// content to remove files and directories from it.
mode_t mode;
if (SystemTools::GetPermissions(source, mode)) {
#if defined(_WIN32) && !defined(__CYGWIN__)
mode |= S_IWRITE;
#else
mode |= S_IWUSR;
#endif
SystemTools::SetPermissions(source, mode);
}
Directory dir;
dir.Load(source);
size_t fileNum;
for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") &&
strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) {
std::string fullPath = source;
fullPath += "/";
fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
if (SystemTools::FileIsDirectory(fullPath) &&
!SystemTools::FileIsSymlink(fullPath)) {
if (!SystemTools::RemoveADirectory(fullPath)) {
return false;
}
} else {
if (!SystemTools::RemoveFile(fullPath)) {
return false;
}
}
}
}
return (Rmdir(source) == 0);
}
/**
*/
size_t SystemTools::GetMaximumFilePathLength()
{
return KWSYS_SYSTEMTOOLS_MAXPATH;
}
/**
* Find the file the given name. Searches the given path and then
* the system search path. Returns the full path to the file if it is
* found. Otherwise, the empty string is returned.
*/
std::string SystemToolsStatic::FindName(
const std::string& name, const std::vector<std::string>& userPaths,
bool no_system_path)
{
// Add the system search path to our path first
std::vector<std::string> path;
if (!no_system_path) {
SystemTools::GetPath(path, "CMAKE_FILE_PATH");
SystemTools::GetPath(path);
}
// now add the additional paths
path.reserve(path.size() + userPaths.size());
path.insert(path.end(), userPaths.begin(), userPaths.end());
// now look for the file
std::string tryPath;
for (std::string const& p : path) {
tryPath = p;
if (tryPath.empty() || tryPath.back() != '/') {
tryPath += '/';
}
tryPath += name;
if (SystemTools::FileExists(tryPath)) {
return tryPath;
}
}
// Couldn't find the file.
return "";
}
/**
* Find the file the given name. Searches the given path and then
* the system search path. Returns the full path to the file if it is
* found. Otherwise, the empty string is returned.
*/
std::string SystemTools::FindFile(const std::string& name,
const std::vector<std::string>& userPaths,
bool no_system_path)
{
std::string tryPath =
SystemToolsStatic::FindName(name, userPaths, no_system_path);
if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
// Couldn't find the file.
return "";
}
/**
* Find the directory the given name. Searches the given path and then
* the system search path. Returns the full path to the directory if it is
* found. Otherwise, the empty string is returned.
*/
std::string SystemTools::FindDirectory(
const std::string& name, const std::vector<std::string>& userPaths,
bool no_system_path)
{
std::string tryPath =
SystemToolsStatic::FindName(name, userPaths, no_system_path);
if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
// Couldn't find the file.
return "";
}
/**
* Find the executable with the given name. Searches the given path and then
* the system search path. Returns the full path to the executable if it is
* found. Otherwise, the empty string is returned.
*/
std::string SystemTools::FindProgram(const char* nameIn,
const std::vector<std::string>& userPaths,
bool no_system_path)
{
if (!nameIn || !*nameIn) {
return "";
}
return SystemTools::FindProgram(std::string(nameIn), userPaths,
no_system_path);
}
std::string SystemTools::FindProgram(const std::string& name,
const std::vector<std::string>& userPaths,
bool no_system_path)
{
std::string tryPath;
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
std::vector<std::string> extensions;
// check to see if the name already has a .xxx at
// the end of it
// on windows try .com then .exe
if (name.size() <= 3 || name[name.size() - 4] != '.') {
extensions.emplace_back(".com");
extensions.emplace_back(".exe");
// first try with extensions if the os supports them
for (std::string const& ext : extensions) {
tryPath = name;
tryPath += ext;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
}
}
#endif
// now try just the name
if (SystemTools::FileExists(name, true)) {
return SystemTools::CollapseFullPath(name);
}
// now construct the path
std::vector<std::string> path;
// Add the system search path to our path.
if (!no_system_path) {
SystemTools::GetPath(path);
}
// now add the additional paths
path.reserve(path.size() + userPaths.size());
path.insert(path.end(), userPaths.begin(), userPaths.end());
// Add a trailing slash to all paths to aid the search process.
for (std::string& p : path) {
if (p.empty() || p.back() != '/') {
p += '/';
}
}
// Try each path
for (std::string& p : path) {
#ifdef _WIN32
// Remove double quotes from the path on windows
SystemTools::ReplaceString(p, "\"", "");
#endif
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
// first try with extensions
for (std::string const& ext : extensions) {
tryPath = p;
tryPath += name;
tryPath += ext;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
}
#endif
// now try it without them
tryPath = p;
tryPath += name;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
}
// Couldn't find the program.
return "";
}
std::string SystemTools::FindProgram(const std::vector<std::string>& names,
const std::vector<std::string>& path,
bool noSystemPath)
{
for (std::string const& name : names) {
// Try to find the program.
std::string result = SystemTools::FindProgram(name, path, noSystemPath);
if (!result.empty()) {
return result;
}
}
return "";
}
/**
* Find the library with the given name. Searches the given path and then
* the system search path. Returns the full path to the library if it is
* found. Otherwise, the empty string is returned.
*/
std::string SystemTools::FindLibrary(const std::string& name,
const std::vector<std::string>& userPaths)
{
// See if the executable exists as written.
if (SystemTools::FileExists(name, true)) {
return SystemTools::CollapseFullPath(name);
}
// Add the system search path to our path.
std::vector<std::string> path;
SystemTools::GetPath(path);
// now add the additional paths
path.reserve(path.size() + userPaths.size());
path.insert(path.end(), userPaths.begin(), userPaths.end());
// Add a trailing slash to all paths to aid the search process.
for (std::string& p : path) {
if (p.empty() || p.back() != '/') {
p += '/';
}
}
std::string tryPath;
for (std::string const& p : path) {
#if defined(__APPLE__)
tryPath = p;
tryPath += name;
tryPath += ".framework";
if (SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
#endif
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
tryPath = p;
tryPath += name;
tryPath += ".lib";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
#else
tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".so";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".a";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".sl";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".dylib";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".dll";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
#endif
}
// Couldn't find the library.
return "";
}
std::string SystemTools::GetRealPath(const std::string& path,
std::string* errorMessage)
{
std::string ret;
Realpath(path, ret, errorMessage);
return ret;
}
bool SystemTools::FileIsDirectory(const std::string& inName)
{
if (inName.empty()) {
return false;
}
size_t length = inName.size();
const char* name = inName.c_str();
// Remove any trailing slash from the name except in a root component.
char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
std::string string_buffer;
size_t last = length - 1;
if (last > 0 && (name[last] == '/' || name[last] == '\\') &&
strcmp(name, "/") != 0 && name[last - 1] != ':') {
if (last < sizeof(local_buffer)) {
memcpy(local_buffer, name, last);
local_buffer[last] = '\0';
name = local_buffer;
} else {
string_buffer.append(name, last);
name = string_buffer.c_str();
}
}
// Now check the file node type.
#if defined(_WIN32)
DWORD attr =
GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str());
if (attr != INVALID_FILE_ATTRIBUTES) {
return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
#else
struct stat fs;
if (stat(name, &fs) == 0) {
return S_ISDIR(fs.st_mode);
#endif
} else {
return false;
}
}
bool SystemTools::FileIsSymlink(const std::string& name)
{
#if defined(_WIN32)
std::wstring path = Encoding::ToWindowsExtendedPath(name);
DWORD attr = GetFileAttributesW(path.c_str());
if (attr != INVALID_FILE_ATTRIBUTES) {
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
// FILE_ATTRIBUTE_REPARSE_POINT means:
// * a file or directory that has an associated reparse point, or
// * a file that is a symbolic link.
HANDLE hFile = CreateFileW(
path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
DWORD bytesReturned = 0;
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned,
nullptr)) {
CloseHandle(hFile);
// Since FILE_ATTRIBUTE_REPARSE_POINT is set this file must be
// a symbolic link if it is not a reparse point.
return GetLastError() == ERROR_NOT_A_REPARSE_POINT;
}
CloseHandle(hFile);
ULONG reparseTag =
reinterpret_cast<PREPARSE_GUID_DATA_BUFFER>(&buffer[0])->ReparseTag;
return (reparseTag == IO_REPARSE_TAG_SYMLINK) ||
(reparseTag == IO_REPARSE_TAG_MOUNT_POINT);
}
return false;
} else {
return false;
}
#else
struct stat fs;
if (lstat(name.c_str(), &fs) == 0) {
return S_ISLNK(fs.st_mode);
} else {
return false;
}
#endif
}
bool SystemTools::FileIsFIFO(const std::string& name)
{
#if defined(_WIN32)
HANDLE hFile =
CreateFileW(Encoding::ToWide(name).c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
const DWORD type = GetFileType(hFile);
CloseHandle(hFile);
return type == FILE_TYPE_PIPE;
#else
struct stat fs;
if (lstat(name.c_str(), &fs) == 0) {
return S_ISFIFO(fs.st_mode);
} else {
return false;
}
#endif
}
#if defined(_WIN32) && !defined(__CYGWIN__)
bool SystemTools::CreateSymlink(const std::string&, const std::string&)
{
return false;
}
#else
bool SystemTools::CreateSymlink(const std::string& origName,
const std::string& newName)
{
return symlink(origName.c_str(), newName.c_str()) >= 0;
}
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
bool SystemTools::ReadSymlink(const std::string&, std::string&)
{
return false;
}
#else
bool SystemTools::ReadSymlink(const std::string& newName,
std::string& origName)
{
char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1];
int count = static_cast<int>(
readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH));
if (count >= 0) {
// Add null-terminator.
buf[count] = 0;
origName = buf;
return true;
} else {
return false;
}
}
#endif
int SystemTools::ChangeDirectory(const std::string& dir)
{
return Chdir(dir);
}
std::string SystemTools::GetCurrentWorkingDirectory(bool collapse)
{
char buf[2048];
const char* cwd = Getcwd(buf, 2048);
std::string path;
if (cwd) {
path = cwd;
}
if (collapse) {
return SystemTools::CollapseFullPath(path);
}
return path;
}
std::string SystemTools::GetProgramPath(const std::string& in_name)
{
std::string dir, file;
SystemTools::SplitProgramPath(in_name, dir, file);
return dir;
}
bool SystemTools::SplitProgramPath(const std::string& in_name,
std::string& dir, std::string& file, bool)
{
dir = in_name;
file = "";
SystemTools::ConvertToUnixSlashes(dir);
if (!SystemTools::FileIsDirectory(dir)) {
std::string::size_type slashPos = dir.rfind("/");
if (slashPos != std::string::npos) {
file = dir.substr(slashPos + 1);
dir = dir.substr(0, slashPos);
} else {
file = dir;
dir = "";
}
}
if (!(dir.empty()) && !SystemTools::FileIsDirectory(dir)) {
std::string oldDir = in_name;
SystemTools::ConvertToUnixSlashes(oldDir);
dir = in_name;
return false;
}
return true;
}
bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut,
std::string& errorMsg, const char* exeName,
const char* buildDir,
const char* installPrefix)
{
std::vector<std::string> failures;
std::string self = argv0 ? argv0 : "";
failures.push_back(self);
SystemTools::ConvertToUnixSlashes(self);
self = SystemTools::FindProgram(self);
if (!SystemTools::FileExists(self)) {
if (buildDir) {
std::string intdir = ".";
#ifdef CMAKE_INTDIR
intdir = CMAKE_INTDIR;
#endif
self = buildDir;
self += "/bin/";
self += intdir;
self += "/";
self += exeName;
self += SystemTools::GetExecutableExtension();
}
}
if (installPrefix) {
if (!SystemTools::FileExists(self)) {
failures.push_back(self);
self = installPrefix;
self += "/bin/";
self += exeName;
}
}
if (!SystemTools::FileExists(self)) {
failures.push_back(self);
std::ostringstream msg;
msg << "Can not find the command line program ";
if (exeName) {
msg << exeName;
}
msg << "\n";
if (argv0) {
msg << " argv[0] = \"" << argv0 << "\"\n";
}
msg << " Attempted paths:\n";
for (std::string const& ff : failures) {
msg << " \"" << ff << "\"\n";
}
errorMsg = msg.str();
return false;
}
pathOut = self;
return true;
}
std::string SystemTools::CollapseFullPath(const std::string& in_relative)
{
return SystemTools::CollapseFullPath(in_relative, nullptr);
}
#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
void SystemTools::AddTranslationPath(const std::string& a,
const std::string& b)
{
std::string path_a = a;
std::string path_b = b;
SystemTools::ConvertToUnixSlashes(path_a);
SystemTools::ConvertToUnixSlashes(path_b);
// First check this is a directory path, since we don't want the table to
// grow too fat
if (SystemTools::FileIsDirectory(path_a)) {
// Make sure the path is a full path and does not contain no '..'
// Ken--the following code is incorrect. .. can be in a valid path
// for example /home/martink/MyHubba...Hubba/Src
if (SystemTools::FileIsFullPath(path_b) &&
path_b.find("..") == std::string::npos) {
// Before inserting make sure path ends with '/'
if (!path_a.empty() && path_a.back() != '/') {
path_a += '/';
}
if (!path_b.empty() && path_b.back() != '/') {
path_b += '/';
}
if (!(path_a == path_b)) {
SystemTools::Statics->TranslationMap.insert(
SystemToolsStatic::StringMap::value_type(std::move(path_a),
std::move(path_b)));
}
}
}
}
void SystemTools::AddKeepPath(const std::string& dir)
{
std::string cdir;
Realpath(SystemTools::CollapseFullPath(dir), cdir);
SystemTools::AddTranslationPath(cdir, dir);
}
void SystemTools::CheckTranslationPath(std::string& path)
{
// Do not translate paths that are too short to have meaningful
// translations.
if (path.size() < 2) {
return;
}
// Always add a trailing slash before translation. It does not
// matter if this adds an extra slash, but we do not want to
// translate part of a directory (like the foo part of foo-dir).
path += '/';
// In case a file was specified we still have to go through this:
// Now convert any path found in the table back to the one desired:
for (auto const& pair : SystemTools::Statics->TranslationMap) {
// We need to check of the path is a substring of the other path
if (path.find(pair.first) == 0) {
path = path.replace(0, pair.first.size(), pair.second);
}
}
// Remove the trailing slash we added before.
path.pop_back();
}
#endif
static void SystemToolsAppendComponents(
std::vector<std::string>& out_components,
std::vector<std::string>::iterator first,
std::vector<std::string>::iterator last)
{
static const std::string up = "..";
static const std::string cur = ".";
for (std::vector<std::string>::const_iterator i = first; i != last; ++i) {
if (*i == up) {
// Remove the previous component if possible. Ignore ../ components
// that try to go above the root. Keep ../ components if they are
// at the beginning of a relative path (base path is relative).
if (out_components.size() > 1 && out_components.back() != up) {
out_components.resize(out_components.size() - 1);
} else if (!out_components.empty() && out_components[0].empty()) {
out_components.emplace_back(std::move(*i));
}
} else if (!i->empty() && *i != cur) {
out_components.emplace_back(std::move(*i));
}
}
}
std::string SystemTools::CollapseFullPath(const std::string& in_path,
const char* in_base)
{
// Use the current working directory as a base path.
char buf[2048];
const char* res_in_base = in_base;
if (!res_in_base) {
if (const char* cwd = Getcwd(buf, 2048)) {
res_in_base = cwd;
} else {
res_in_base = "";
}
}
return SystemTools::CollapseFullPath(in_path, std::string(res_in_base));
}
std::string SystemTools::CollapseFullPath(const std::string& in_path,
const std::string& in_base)
{
// Collect the output path components.
std::vector<std::string> out_components;
// Split the input path components.
std::vector<std::string> path_components;
SystemTools::SplitPath(in_path, path_components);
out_components.reserve(path_components.size());
// If the input path is relative, start with a base path.
if (path_components[0].empty()) {
std::vector<std::string> base_components;
// Use the given base path.
SystemTools::SplitPath(in_base, base_components);
// Append base path components to the output path.
out_components.push_back(base_components[0]);
SystemToolsAppendComponents(out_components, base_components.begin() + 1,
base_components.end());
}
// Append input path components to the output path.
SystemToolsAppendComponents(out_components, path_components.begin(),
path_components.end());
// Transform the path back to a string.
std::string newPath = SystemTools::JoinPath(out_components);
#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
// Update the translation table with this potentially new path. I am not
// sure why this line is here, it seems really questionable, but yet I
// would put good money that if I remove it something will break, basically
// from what I can see it created a mapping from the collapsed path, to be
// replaced by the input path, which almost completely does the opposite of
// this function, the only thing preventing this from happening a lot is
// that if the in_path has a .. in it, then it is not added to the
// translation table. So for most calls this either does nothing due to the
// .. or it adds a translation between identical paths as nothing was
// collapsed, so I am going to try to comment it out, and see what hits the
// fan, hopefully quickly.
// Commented out line below:
// SystemTools::AddTranslationPath(newPath, in_path);
SystemTools::CheckTranslationPath(newPath);
#endif
#ifdef _WIN32
newPath = SystemTools::Statics->GetActualCaseForPathCached(newPath);
SystemTools::ConvertToUnixSlashes(newPath);
#endif
// Return the reconstructed path.
return newPath;
}
// compute the relative path from here to there
std::string SystemTools::RelativePath(const std::string& local,
const std::string& remote)
{
if (!SystemTools::FileIsFullPath(local)) {
return "";
}
if (!SystemTools::FileIsFullPath(remote)) {
return "";
}
std::string l = SystemTools::CollapseFullPath(local);
std::string r = SystemTools::CollapseFullPath(remote);
// split up both paths into arrays of strings using / as a separator
std::vector<std::string> localSplit = SystemTools::SplitString(l, '/', true);
std::vector<std::string> remoteSplit =
SystemTools::SplitString(r, '/', true);
std::vector<std::string>
commonPath; // store shared parts of path in this array
std::vector<std::string> finalPath; // store the final relative path here
// count up how many matching directory names there are from the start
unsigned int sameCount = 0;
while (((sameCount <= (localSplit.size() - 1)) &&
(sameCount <= (remoteSplit.size() - 1))) &&
// for Windows and Apple do a case insensitive string compare
#if defined(_WIN32) || defined(__APPLE__)
SystemTools::Strucmp(localSplit[sameCount].c_str(),
remoteSplit[sameCount].c_str()) == 0
#else
localSplit[sameCount] == remoteSplit[sameCount]
#endif
) {
// put the common parts of the path into the commonPath array
commonPath.push_back(localSplit[sameCount]);
// erase the common parts of the path from the original path arrays
localSplit[sameCount] = "";
remoteSplit[sameCount] = "";
sameCount++;
}
// If there is nothing in common at all then just return the full
// path. This is the case only on windows when the paths have
// different drive letters. On unix two full paths always at least
// have the root "/" in common so we will return a relative path
// that passes through the root directory.
if (sameCount == 0) {
return remote;
}
// for each entry that is not common in the local path
// add a ../ to the finalpath array, this gets us out of the local
// path into the remote dir
for (std::string const& lp : localSplit) {
if (!lp.empty()) {
finalPath.emplace_back("../");
}
}
// for each entry that is not common in the remote path add it
// to the final path.
for (std::string const& rp : remoteSplit) {
if (!rp.empty()) {
finalPath.push_back(rp);
}
}
std::string relativePath; // result string
// now turn the array of directories into a unix path by puttint /
// between each entry that does not already have one
for (std::string const& fp : finalPath) {
if (!relativePath.empty() && relativePath.back() != '/') {
relativePath += '/';
}
relativePath += fp;
}
return relativePath;
}
std::string SystemTools::GetActualCaseForPath(const std::string& p)
{
#ifdef _WIN32
return SystemToolsStatic::GetCasePathName(p);
#else
return p;
#endif
}
const char* SystemTools::SplitPathRootComponent(const std::string& p,
std::string* root)
{
// Identify the root component.
const char* c = p.c_str();
if ((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\')) {
// Network path.
if (root) {
*root = "//";
}
c += 2;
} else if (c[0] == '/' || c[0] == '\\') {
// Unix path (or Windows path w/out drive letter).
if (root) {
*root = "/";
}
c += 1;
} else if (c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\')) {
// Windows path.
if (root) {
(*root) = "_:/";
(*root)[0] = c[0];
}
c += 3;
} else if (c[0] && c[1] == ':') {
// Path relative to a windows drive working directory.
if (root) {
(*root) = "_:";
(*root)[0] = c[0];
}
c += 2;
} else if (c[0] == '~') {
// Home directory. The returned root should always have a
// trailing slash so that appending components as
// c[0]c[1]/c[2]/... works. The remaining path returned should
// skip the first slash if it exists:
//
// "~" : root = "~/" , return ""
// "~/ : root = "~/" , return ""
// "~/x : root = "~/" , return "x"
// "~u" : root = "~u/", return ""
// "~u/" : root = "~u/", return ""
// "~u/x" : root = "~u/", return "x"
size_t n = 1;
while (c[n] && c[n] != '/') {
++n;
}
if (root) {
root->assign(c, n);
*root += '/';
}
if (c[n] == '/') {
++n;
}
c += n;
} else {
// Relative path.
if (root) {
*root = "";
}
}
// Return the remaining path.
return c;
}
void SystemTools::SplitPath(const std::string& p,
std::vector<std::string>& components,
bool expand_home_dir)
{
const char* c;
components.clear();
// Identify the root component.
{
std::string root;
c = SystemTools::SplitPathRootComponent(p, &root);
// Expand home directory references if requested.
if (expand_home_dir && !root.empty() && root[0] == '~') {
std::string homedir;
root = root.substr(0, root.size() - 1);
if (root.size() == 1) {
#if defined(_WIN32) && !defined(__CYGWIN__)
if (!SystemTools::GetEnv("USERPROFILE", homedir))
#endif
SystemTools::GetEnv("HOME", homedir);
}
#ifdef HAVE_GETPWNAM
else if (passwd* pw = getpwnam(root.c_str() + 1)) {
if (pw->pw_dir) {
homedir = pw->pw_dir;
}
}
#endif
if (!homedir.empty() &&
(homedir.back() == '/' || homedir.back() == '\\')) {
homedir.resize(homedir.size() - 1);
}
SystemTools::SplitPath(homedir, components);
} else {
components.push_back(root);
}
}
// Parse the remaining components.
const char* first = c;
const char* last = first;
for (; *last; ++last) {
if (*last == '/' || *last == '\\') {
// End of a component. Save it.
components.push_back(std::string(first, last));
first = last + 1;
}
}
// Save the last component unless there were no components.
if (last != c) {
components.push_back(std::string(first, last));
}
}
std::string SystemTools::JoinPath(const std::vector<std::string>& components)
{
return SystemTools::JoinPath(components.begin(), components.end());
}
std::string SystemTools::JoinPath(
std::vector<std::string>::const_iterator first,
std::vector<std::string>::const_iterator last)
{
// Construct result in a single string.
std::string result;
size_t len = 0;
for (std::vector<std::string>::const_iterator i = first; i != last; ++i) {
len += 1 + i->size();
}
result.reserve(len);
// The first two components do not add a slash.
if (first != last) {
result.append(*first++);
}
if (first != last) {
result.append(*first++);
}
// All remaining components are always separated with a slash.
while (first != last) {
result.push_back('/');
result.append((*first++));
}
// Return the concatenated result.
return result;
}
bool SystemTools::ComparePath(const std::string& c1, const std::string& c2)
{
#if defined(_WIN32) || defined(__APPLE__)
# ifdef _MSC_VER
return _stricmp(c1.c_str(), c2.c_str()) == 0;
# elif defined(__APPLE__) || defined(__GNUC__)
return strcasecmp(c1.c_str(), c2.c_str()) == 0;
# else
return SystemTools::Strucmp(c1.c_str(), c2.c_str()) == 0;
# endif
#else
return c1 == c2;
#endif
}
bool SystemTools::Split(const std::string& str,
std::vector<std::string>& lines, char separator)
{
std::string data(str);
std::string::size_type lpos = 0;
while (lpos < data.length()) {
std::string::size_type rpos = data.find_first_of(separator, lpos);
if (rpos == std::string::npos) {
// String ends at end of string without a separator.
lines.push_back(data.substr(lpos));
return false;
} else {
// String ends in a separator, remove the character.
lines.push_back(data.substr(lpos, rpos - lpos));
}
lpos = rpos + 1;
}
return true;
}
bool SystemTools::Split(const std::string& str,
std::vector<std::string>& lines)
{
std::string data(str);
std::string::size_type lpos = 0;
while (lpos < data.length()) {
std::string::size_type rpos = data.find_first_of('\n', lpos);
if (rpos == std::string::npos) {
// Line ends at end of string without a newline.
lines.push_back(data.substr(lpos));
return false;
}
if ((rpos > lpos) && (data[rpos - 1] == '\r')) {
// Line ends in a "\r\n" pair, remove both characters.
lines.push_back(data.substr(lpos, (rpos - 1) - lpos));
} else {
// Line ends in a "\n", remove the character.
lines.push_back(data.substr(lpos, rpos - lpos));
}
lpos = rpos + 1;
}
return true;
}
/**
* Return path of a full filename (no trailing slashes).
* Warning: returned path is converted to Unix slashes format.
*/
std::string SystemTools::GetFilenamePath(const std::string& filename)
{
std::string fn = filename;
SystemTools::ConvertToUnixSlashes(fn);
std::string::size_type slash_pos = fn.rfind("/");
if (slash_pos != std::string::npos) {
std::string ret = fn.substr(0, slash_pos);
if (ret.size() == 2 && ret[1] == ':') {
return ret + '/';
}
if (ret.empty()) {
return "/";
}
return ret;
} else {
return "";
}
}
/**
* Return file name of a full filename (i.e. file name without path).
*/
std::string SystemTools::GetFilenameName(const std::string& filename)
{
#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES)
const char* separators = "/\\";
#else
char separators = '/';
#endif
std::string::size_type slash_pos = filename.find_last_of(separators);
if (slash_pos != std::string::npos) {
return filename.substr(slash_pos + 1);
} else {
return filename;
}
}
/**
* Return file extension of a full filename (dot included).
* Warning: this is the longest extension (for example: .tar.gz)
*/
std::string SystemTools::GetFilenameExtension(const std::string& filename)
{
std::string name = SystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.find('.');
if (dot_pos != std::string::npos) {
return name.substr(dot_pos);
} else {
return "";
}
}
/**
* Return file extension of a full filename (dot included).
* Warning: this is the shortest extension (for example: .gz of .tar.gz)
*/
std::string SystemTools::GetFilenameLastExtension(const std::string& filename)
{
std::string name = SystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.rfind('.');
if (dot_pos != std::string::npos) {
return name.substr(dot_pos);
} else {
return "";
}
}
/**
* Return file name without extension of a full filename (i.e. without path).
* Warning: it considers the longest extension (for example: .tar.gz)
*/
std::string SystemTools::GetFilenameWithoutExtension(
const std::string& filename)
{
std::string name = SystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.find('.');
if (dot_pos != std::string::npos) {
return name.substr(0, dot_pos);
} else {
return name;
}
}
/**
* Return file name without extension of a full filename (i.e. without path).
* Warning: it considers the last extension (for example: removes .gz
* from .tar.gz)
*/
std::string SystemTools::GetFilenameWithoutLastExtension(
const std::string& filename)
{
std::string name = SystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.rfind('.');
if (dot_pos != std::string::npos) {
return name.substr(0, dot_pos);
} else {
return name;
}
}
bool SystemTools::FileHasSignature(const char* filename, const char* signature,
long offset)
{
if (!filename || !signature) {
return false;
}
FILE* fp = Fopen(filename, "rb");
if (!fp) {
return false;
}
fseek(fp, offset, SEEK_SET);
bool res = false;
size_t signature_len = strlen(signature);
char* buffer = new char[signature_len];
if (fread(buffer, 1, signature_len, fp) == signature_len) {
res = (!strncmp(buffer, signature, signature_len) ? true : false);
}
delete[] buffer;
fclose(fp);
return res;
}
SystemTools::FileTypeEnum SystemTools::DetectFileType(const char* filename,
unsigned long length,
double percent_bin)
{
if (!filename || percent_bin < 0) {
return SystemTools::FileTypeUnknown;
}
if (SystemTools::FileIsDirectory(filename)) {
return SystemTools::FileTypeUnknown;
}
FILE* fp = Fopen(filename, "rb");
if (!fp) {
return SystemTools::FileTypeUnknown;
}
// Allocate buffer and read bytes
unsigned char* buffer = new unsigned char[length];
size_t read_length = fread(buffer, 1, length, fp);
fclose(fp);
if (read_length == 0) {
delete[] buffer;
return SystemTools::FileTypeUnknown;
}
// Loop over contents and count
size_t text_count = 0;
const unsigned char* ptr = buffer;
const unsigned char* buffer_end = buffer + read_length;
while (ptr != buffer_end) {
if ((*ptr >= 0x20 && *ptr <= 0x7F) || *ptr == '\n' || *ptr == '\r' ||
*ptr == '\t') {
text_count++;
}
ptr++;
}
delete[] buffer;
double current_percent_bin = (static_cast<double>(read_length - text_count) /
static_cast<double>(read_length));
if (current_percent_bin >= percent_bin) {
return SystemTools::FileTypeBinary;
}
return SystemTools::FileTypeText;
}
bool SystemTools::LocateFileInDir(const char* filename, const char* dir,
std::string& filename_found,
int try_filename_dirs)
{
if (!filename || !dir) {
return false;
}
// Get the basename of 'filename'
std::string filename_base = SystemTools::GetFilenameName(filename);
// Check if 'dir' is really a directory
// If win32 and matches something like C:, accept it as a dir
std::string real_dir;
if (!SystemTools::FileIsDirectory(dir)) {
#if defined(_WIN32)
size_t dir_len = strlen(dir);
if (dir_len < 2 || dir[dir_len - 1] != ':') {
#endif
real_dir = SystemTools::GetFilenamePath(dir);
dir = real_dir.c_str();
#if defined(_WIN32)
}
#endif
}
// Try to find the file in 'dir'
bool res = false;
if (!filename_base.empty() && dir) {
size_t dir_len = strlen(dir);
int need_slash =
(dir_len && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\');
std::string temp = dir;
if (need_slash) {
temp += "/";
}
temp += filename_base;
if (SystemTools::FileExists(temp)) {
res = true;
filename_found = temp;
}
// If not found, we can try harder by appending part of the file to
// to the directory to look inside.
// Example: if we were looking for /foo/bar/yo.txt in /d1/d2, then
// try to find yo.txt in /d1/d2/bar, then /d1/d2/foo/bar, etc.
else if (try_filename_dirs) {
std::string filename_dir(filename);
std::string filename_dir_base;
std::string filename_dir_bases;
do {
filename_dir = SystemTools::GetFilenamePath(filename_dir);
filename_dir_base = SystemTools::GetFilenameName(filename_dir);
#if defined(_WIN32)
if (filename_dir_base.empty() || filename_dir_base.back() == ':')
#else
if (filename_dir_base.empty())
#endif
{
break;
}
filename_dir_bases = filename_dir_base + "/" + filename_dir_bases;
temp = dir;
if (need_slash) {
temp += "/";
}
temp += filename_dir_bases;
res = SystemTools::LocateFileInDir(filename_base.c_str(), temp.c_str(),
filename_found, 0);
} while (!res && !filename_dir_base.empty());
}
}
return res;
}
bool SystemTools::FileIsFullPath(const std::string& in_name)
{
return SystemToolsStatic::FileIsFullPath(in_name.c_str(), in_name.size());
}
bool SystemTools::FileIsFullPath(const char* in_name)
{
return SystemToolsStatic::FileIsFullPath(
in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0);
}
bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len)
{
#if defined(_WIN32) || defined(__CYGWIN__)
// On Windows, the name must be at least two characters long.
if (len < 2) {
return false;
}
if (in_name[1] == ':') {
return true;
}
if (in_name[0] == '\\') {
return true;
}
#else
// On UNIX, the name must be at least one character long.
if (len < 1) {
return false;
}
#endif
#if !defined(_WIN32)
if (in_name[0] == '~') {
return true;
}
#endif
// On UNIX, the name must begin in a '/'.
// On Windows, if the name begins in a '/', then it is a full
// network path.
if (in_name[0] == '/') {
return true;
}
return false;
}
bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
std::string tempPath = path; // create a buffer
// if the path passed in has quotes around it, first remove the quotes
if (!path.empty() && path[0] == '"' && path.back() == '"') {
tempPath = path.substr(1, path.length() - 2);
}
std::wstring wtempPath = Encoding::ToWide(tempPath);
DWORD ret = GetShortPathNameW(wtempPath.c_str(), nullptr, 0);
std::vector<wchar_t> buffer(ret);
if (ret != 0) {
ret = GetShortPathNameW(wtempPath.c_str(), &buffer[0],
static_cast<DWORD>(buffer.size()));
}
if (ret == 0) {
return false;
} else {
shortPath = Encoding::ToNarrow(&buffer[0]);
return true;
}
#else
shortPath = path;
return true;
#endif
}
std::string SystemTools::GetCurrentDateTime(const char* format)
{
char buf[1024];
time_t t;
time(&t);
strftime(buf, sizeof(buf), format, localtime(&t));
return std::string(buf);
}
std::string SystemTools::MakeCidentifier(const std::string& s)
{
std::string str(s);
if (str.find_first_of("0123456789") == 0) {
str = "_" + str;
}
std::string permited_chars("_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789");
std::string::size_type pos = 0;
while ((pos = str.find_first_not_of(permited_chars, pos)) !=
std::string::npos) {
str[pos] = '_';
}
return str;
}
// Convenience function around std::getline which removes a trailing carriage
// return and can truncate the buffer as needed. Returns true
// if any data were read before the end-of-file was reached.
bool SystemTools::GetLineFromStream(std::istream& is, std::string& line,
bool* has_newline /* = 0 */,
long sizeLimit /* = -1 */)
{
// Start with an empty line.
line = "";
// 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;
}
std::getline(is, line);
bool haveData = !line.empty() || !is.eof();
if (!line.empty()) {
// Avoid storing a carriage return character.
if (line.back() == '\r') {
line.resize(line.size() - 1);
}
// if we read too much then truncate the buffer
if (sizeLimit >= 0 && line.size() >= static_cast<size_t>(sizeLimit)) {
line.resize(sizeLimit);
}
}
// Return the results.
if (has_newline) {
*has_newline = !is.eof();
}
return haveData;
}
int SystemTools::GetTerminalWidth()
{
int width = -1;
#ifdef HAVE_TTY_INFO
struct winsize ws;
std::string columns; /* Unix98 environment variable */
if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0 && ws.ws_row > 0) {
width = ws.ws_col;
}
if (!isatty(STDOUT_FILENO)) {
width = -1;
}
if (SystemTools::GetEnv("COLUMNS", columns) && !columns.empty()) {
long t;
char* endptr;
t = strtol(columns.c_str(), &endptr, 0);
if (endptr && !*endptr && (t > 0) && (t < 1000)) {
width = static_cast<int>(t);
}
}
if (width < 9) {
width = -1;
}
#endif
return width;
}
bool SystemTools::GetPermissions(const char* file, mode_t& mode)
{
if (!file) {
return false;
}
return SystemTools::GetPermissions(std::string(file), mode);
}
bool SystemTools::GetPermissions(const std::string& file, mode_t& mode)
{
#if defined(_WIN32)
DWORD attr =
GetFileAttributesW(Encoding::ToWindowsExtendedPath(file).c_str());
if (attr == INVALID_FILE_ATTRIBUTES) {
return false;
}
if ((attr & FILE_ATTRIBUTE_READONLY) != 0) {
mode = (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
} else {
mode = (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6)) |
(_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
}
if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
mode |= S_IFDIR | (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6));
} else {
mode |= S_IFREG;
}
size_t dotPos = file.rfind('.');
const char* ext = dotPos == std::string::npos ? 0 : (file.c_str() + dotPos);
if (ext &&
(Strucmp(ext, ".exe") == 0 || Strucmp(ext, ".com") == 0 ||
Strucmp(ext, ".cmd") == 0 || Strucmp(ext, ".bat") == 0)) {
mode |= (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6));
}
#else
struct stat st;
if (stat(file.c_str(), &st) < 0) {
return false;
}
mode = st.st_mode;
#endif
return true;
}
bool SystemTools::SetPermissions(const char* file, mode_t mode,
bool honor_umask)
{
if (!file) {
return false;
}
return SystemTools::SetPermissions(std::string(file), mode, honor_umask);
}
bool SystemTools::SetPermissions(const std::string& file, mode_t mode,
bool honor_umask)
{
if (!SystemTools::PathExists(file)) {
return false;
}
if (honor_umask) {
mode_t currentMask = umask(0);
umask(currentMask);
mode &= ~currentMask;
}
#ifdef _WIN32
if (_wchmod(Encoding::ToWindowsExtendedPath(file).c_str(), mode) < 0)
#else
if (chmod(file.c_str(), mode) < 0)
#endif
{
return false;
}
return true;
}
std::string SystemTools::GetParentDirectory(const std::string& fileOrDir)
{
return SystemTools::GetFilenamePath(fileOrDir);
}
bool SystemTools::IsSubDirectory(const std::string& cSubdir,
const std::string& cDir)
{
if (cDir.empty()) {
return false;
}
std::string subdir = cSubdir;
std::string dir = cDir;
SystemTools::ConvertToUnixSlashes(subdir);
SystemTools::ConvertToUnixSlashes(dir);
if (subdir.size() <= dir.size() || dir.empty()) {
return false;
}
bool isRootPath = dir.back() == '/'; // like "/" or "C:/"
size_t expectedSlashPosition = isRootPath ? dir.size() - 1u : dir.size();
if (subdir[expectedSlashPosition] != '/') {
return false;
}
std::string s = subdir.substr(0, dir.size());
return SystemTools::ComparePath(s, dir);
}
void SystemTools::Delay(unsigned int msec)
{
#ifdef _WIN32
Sleep(msec);
#else
// The sleep function gives 1 second resolution and the usleep
// function gives 1e-6 second resolution but on some platforms has a
// maximum sleep time of 1 second. This could be re-implemented to
// use select with masked signals or pselect to mask signals
// atomically. If select is given empty sets and zero as the max
// file descriptor but a non-zero timeout it can be used to block
// for a precise amount of time.
if (msec >= 1000) {
sleep(msec / 1000);
usleep((msec % 1000) * 1000);
} else {
usleep(msec * 1000);
}
#endif
}
std::string SystemTools::GetOperatingSystemNameAndVersion()
{
std::string res;
#ifdef _WIN32
char buffer[256];
OSVERSIONINFOEXA osvi;
BOOL bOsVersionInfoEx;
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
# elif defined __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
# endif
bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA*)&osvi);
if (!bOsVersionInfoEx) {
return 0;
}
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# ifdef __clang__
# pragma clang diagnostic pop
# else
# pragma warning(pop)
# endif
# endif
switch (osvi.dwPlatformId) {
// Test for the Windows NT product family.
case VER_PLATFORM_WIN32_NT:
// Test for the specific product family.
if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows 10";
} else {
res += "Microsoft Windows Server 2016 family";
}
}
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows 8.1";
} else {
res += "Microsoft Windows Server 2012 R2 family";
}
}
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows 8";
} else {
res += "Microsoft Windows Server 2012 family";
}
}
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows 7";
} else {
res += "Microsoft Windows Server 2008 R2 family";
}
}
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
if (osvi.wProductType == VER_NT_WORKSTATION) {
res += "Microsoft Windows Vista";
} else {
res += "Microsoft Windows Server 2008 family";
}
}
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
res += "Microsoft Windows Server 2003 family";
}
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
res += "Microsoft Windows XP";
}
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
res += "Microsoft Windows 2000";
}
if (osvi.dwMajorVersion <= 4) {
res += "Microsoft Windows NT";
}
// Test for specific product on Windows NT 4.0 SP6 and later.
if (bOsVersionInfoEx) {
// Test for the workstation type.
if (osvi.wProductType == VER_NT_WORKSTATION) {
if (osvi.dwMajorVersion == 4) {
res += " Workstation 4.0";
} else if (osvi.dwMajorVersion == 5) {
if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
res += " Home Edition";
} else {
res += " Professional";
}
}
}
// Test for the server type.
else if (osvi.wProductType == VER_NT_SERVER) {
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
res += " Datacenter Edition";
} else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
res += " Enterprise Edition";
} else if (osvi.wSuiteMask == VER_SUITE_BLADE) {
res += " Web Edition";
} else {
res += " Standard Edition";
}
}
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
res += " Datacenter Server";
} else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
res += " Advanced Server";
} else {
res += " Server";
}
}
else if (osvi.dwMajorVersion <= 4) // Windows NT 4.0
{
if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
res += " Server 4.0, Enterprise Edition";
} else {
res += " Server 4.0";
}
}
}
}
// Test for specific product on Windows NT 4.0 SP5 and earlier
else {
HKEY hKey;
# define BUFSIZE 80
wchar_t szProductType[BUFSIZE];
DWORD dwBufLen = BUFSIZE;
LONG lRet;
lRet =
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
0, KEY_QUERY_VALUE, &hKey);
if (lRet != ERROR_SUCCESS) {
return 0;
}
lRet = RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr,
(LPBYTE)szProductType, &dwBufLen);
if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE)) {
return 0;
}
RegCloseKey(hKey);
if (lstrcmpiW(L"WINNT", szProductType) == 0) {
res += " Workstation";
}
if (lstrcmpiW(L"LANMANNT", szProductType) == 0) {
res += " Server";
}
if (lstrcmpiW(L"SERVERNT", szProductType) == 0) {
res += " Advanced Server";
}
res += " ";
sprintf(buffer, "%ld", osvi.dwMajorVersion);
res += buffer;
res += ".";
sprintf(buffer, "%ld", osvi.dwMinorVersion);
res += buffer;
}
// Display service pack (if any) and build number.
if (osvi.dwMajorVersion == 4 &&
lstrcmpiA(osvi.szCSDVersion, "Service Pack 6") == 0) {
HKEY hKey;
LONG lRet;
// Test for SP6 versus SP6a.
lRet = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
0, KEY_QUERY_VALUE, &hKey);
if (lRet == ERROR_SUCCESS) {
res += " Service Pack 6a (Build ";
sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
res += buffer;
res += ")";
} else // Windows NT 4.0 prior to SP6a
{
res += " ";
res += osvi.szCSDVersion;
res += " (Build ";
sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
res += buffer;
res += ")";
}
RegCloseKey(hKey);
} else // Windows NT 3.51 and earlier or Windows 2000 and later
{
res += " ";
res += osvi.szCSDVersion;
res += " (Build ";
sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF);
res += buffer;
res += ")";
}
break;
// Test for the Windows 95 product family.
case VER_PLATFORM_WIN32_WINDOWS:
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
res += "Microsoft Windows 95";
if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') {
res += " OSR2";
}
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
res += "Microsoft Windows 98";
if (osvi.szCSDVersion[1] == 'A') {
res += " SE";
}
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
res += "Microsoft Windows Millennium Edition";
}
break;
case VER_PLATFORM_WIN32s:
res += "Microsoft Win32s";
break;
}
#endif
return res;
}
bool SystemTools::ParseURLProtocol(const std::string& URL,
std::string& protocol,
std::string& dataglom)
{
// match 0 entire url
// match 1 protocol
// match 2 dataglom following protocol://
kwsys::RegularExpression urlRe(VTK_URL_PROTOCOL_REGEX);
if (!urlRe.find(URL))
return false;
protocol = urlRe.match(1);
dataglom = urlRe.match(2);
return true;
}
bool SystemTools::ParseURL(const std::string& URL, std::string& protocol,
std::string& username, std::string& password,
std::string& hostname, std::string& dataport,
std::string& database)
{
kwsys::RegularExpression urlRe(VTK_URL_REGEX);
if (!urlRe.find(URL))
return false;
// match 0 URL
// match 1 protocol
// match 2 mangled user
// match 3 username
// match 4 mangled password
// match 5 password
// match 6 hostname
// match 7 mangled port
// match 8 dataport
// match 9 database name
protocol = urlRe.match(1);
username = urlRe.match(3);
password = urlRe.match(5);
hostname = urlRe.match(6);
dataport = urlRe.match(8);
database = urlRe.match(9);
return true;
}
// These must NOT be initialized. Default initialization to zero is
// necessary.
static unsigned int SystemToolsManagerCount;
SystemToolsStatic* SystemTools::Statics;
// 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
// Create statics singleton instance
SystemTools::Statics = new SystemToolsStatic;
#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
// Add some special translation paths for unix. These are not added
// for windows because drive letters need to be maintained. Also,
// there are not sym-links and mount points on windows anyway.
# if !defined(_WIN32) || defined(__CYGWIN__)
// The tmp path is frequently a logical path so always keep it:
SystemTools::AddKeepPath("/tmp/");
// If the current working directory is a logical path then keep the
// logical name.
std::string pwd_str;
if (SystemTools::GetEnv("PWD", pwd_str)) {
char buf[2048];
if (const char* cwd = Getcwd(buf, 2048)) {
// The current working directory may be a logical path. Find
// the shortest logical path that still produces the correct
// physical path.
std::string cwd_changed;
std::string pwd_changed;
// Test progressively shorter logical-to-physical mappings.
std::string cwd_str = cwd;
std::string pwd_path;
Realpath(pwd_str, pwd_path);
while (cwd_str == pwd_path && cwd_str != pwd_str) {
// The current pair of paths is a working logical mapping.
cwd_changed = cwd_str;
pwd_changed = pwd_str;
// Strip off one directory level and see if the logical
// mapping still works.
pwd_str = SystemTools::GetFilenamePath(pwd_str);
cwd_str = SystemTools::GetFilenamePath(cwd_str);
Realpath(pwd_str, pwd_path);
}
// Add the translation to keep the logical path name.
if (!cwd_changed.empty() && !pwd_changed.empty()) {
SystemTools::AddTranslationPath(cwd_changed, pwd_changed);
}
}
}
# endif
#endif
}
void SystemTools::ClassFinalize()
{
delete SystemTools::Statics;
}
} // namespace KWSYS_NAMESPACE
#if defined(_MSC_VER) && defined(_DEBUG)
# include <crtdbg.h>
# include <stdio.h>
# include <stdlib.h>
namespace KWSYS_NAMESPACE {
static int SystemToolsDebugReport(int, char* message, int*)
{
fprintf(stderr, "%s", message);
fflush(stderr);
return 1; // no further reporting required
}
void SystemTools::EnableMSVCDebugHook()
{
if (SystemTools::HasEnv("DART_TEST_FROM_DART") ||
SystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST")) {
_CrtSetReportHook(SystemToolsDebugReport);
}
}
} // namespace KWSYS_NAMESPACE
#else
namespace KWSYS_NAMESPACE {
void SystemTools::EnableMSVCDebugHook()
{
}
} // namespace KWSYS_NAMESPACE
#endif
-981
View File
@@ -1,981 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_SystemTools_hxx
#define @KWSYS_NAMESPACE@_SystemTools_hxx
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <iosfwd>
#include <map>
#include <string>
#include <vector>
#include <sys/types.h>
// include sys/stat.h after sys/types.h
#include <sys/stat.h>
#if !defined(_WIN32) || defined(__CYGWIN__)
# include <unistd.h> // For access permissions for use with access()
#endif
// Required for va_list
#include <stdarg.h>
// Required for FILE*
#include <stdio.h>
#if !defined(va_list)
// Some compilers move va_list into the std namespace and there is no way to
// tell that this has been done. Playing with things being included before or
// after stdarg.h does not solve things because we do not have control over
// what the user does. This hack solves this problem by moving va_list to our
// own namespace that is local for kwsys.
namespace std {
} // Required for platforms that do not have std namespace
namespace @KWSYS_NAMESPACE@_VA_LIST {
using namespace std;
typedef va_list hack_va_list;
}
namespace @KWSYS_NAMESPACE@ {
typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list;
}
#endif // va_list
namespace @KWSYS_NAMESPACE@ {
class SystemToolsStatic;
/** \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();
SystemToolsManager(const SystemToolsManager&) = delete;
SystemToolsManager& operator=(const SystemToolsManager&) = delete;
};
// This instance will show up in any translation unit that uses
// SystemTools. It will make sure SystemTools is initialized
// before it is used and is the last static object destroyed.
static SystemToolsManager SystemToolsManagerInstance;
// Flags for use with TestFileAccess. Use a typedef in case any operating
// system in the future needs a special type. These are flags that may be
// combined using the | operator.
typedef int TestFilePermissions;
#if defined(_WIN32) && !defined(__CYGWIN__)
// On Windows (VC and Borland), no system header defines these constants...
static const TestFilePermissions TEST_FILE_OK = 0;
static const TestFilePermissions TEST_FILE_READ = 4;
static const TestFilePermissions TEST_FILE_WRITE = 2;
static const TestFilePermissions TEST_FILE_EXECUTE = 1;
#else
// Standard POSIX constants
static const TestFilePermissions TEST_FILE_OK = F_OK;
static const TestFilePermissions TEST_FILE_READ = R_OK;
static const TestFilePermissions TEST_FILE_WRITE = W_OK;
static const TestFilePermissions TEST_FILE_EXECUTE = X_OK;
#endif
/** \class SystemTools
* \brief A collection of useful platform-independent system functions.
*/
class @KWSYS_NAMESPACE@_EXPORT SystemTools
{
public:
/** -----------------------------------------------------------------
* String Manipulation Routines
* -----------------------------------------------------------------
*/
/**
* Replace symbols in str that are not valid in C identifiers as
* defined by the 1999 standard, ie. anything except [A-Za-z0-9_].
* They are replaced with `_' and if the first character is a digit
* then an underscore is prepended. Note that this can produce
* identifiers that the standard reserves (_[A-Z].* and __.*).
*/
static std::string MakeCidentifier(const std::string& s);
static std::string MakeCindentifier(const std::string& s)
{
return MakeCidentifier(s);
}
/**
* Replace replace all occurrences of the string in the source string.
*/
static void ReplaceString(std::string& source, const char* replace,
const char* with);
static void ReplaceString(std::string& source, const std::string& replace,
const std::string& with);
/**
* Return a capitalized string (i.e the first letter is uppercased,
* all other are lowercased).
*/
static std::string Capitalized(const std::string&);
/**
* Return a 'capitalized words' string (i.e the first letter of each word
* is uppercased all other are left untouched though).
*/
static std::string CapitalizedWords(const std::string&);
/**
* Return a 'uncapitalized words' string (i.e the first letter of each word
* is lowercased all other are left untouched though).
*/
static std::string UnCapitalizedWords(const std::string&);
/**
* Return a lower case string
*/
static std::string LowerCase(const std::string&);
/**
* Return a lower case string
*/
static std::string UpperCase(const std::string&);
/**
* Count char in string
*/
static size_t CountChar(const char* str, char c);
/**
* Remove some characters from a string.
* Return a pointer to the new resulting string (allocated with 'new')
*/
static char* RemoveChars(const char* str, const char* toremove);
/**
* Remove remove all but 0->9, A->F characters from a string.
* Return a pointer to the new resulting string (allocated with 'new')
*/
static char* RemoveCharsButUpperHex(const char* str);
/**
* Replace some characters by another character in a string (in-place)
* Return a pointer to string
*/
static char* ReplaceChars(char* str, const char* toreplace,
char replacement);
/**
* Returns true if str1 starts (respectively ends) with str2
*/
static bool StringStartsWith(const char* str1, const char* str2);
static bool StringStartsWith(const std::string& str1, const char* str2);
static bool StringEndsWith(const char* str1, const char* str2);
static bool StringEndsWith(const std::string& str1, const char* str2);
/**
* Returns a pointer to the last occurrence of str2 in str1
*/
static const char* FindLastString(const char* str1, const char* str2);
/**
* Make a duplicate of the string similar to the strdup C function
* but use new to create the 'new' string, so one can use
* 'delete' to remove it. Returns 0 if the input is empty.
*/
static char* DuplicateString(const char* str);
/**
* Return the string cropped to a given length by removing chars in the
* center of the string and replacing them with an ellipsis (...)
*/
static std::string CropString(const std::string&, size_t max_len);
/** split a path by separator into an array of strings, default is /.
If isPath is true then the string is treated like a path and if
s starts with a / then the first element of the returned array will
be /, so /foo/bar will be [/, foo, bar]
*/
static std::vector<std::string> SplitString(const std::string& s,
char separator = '/',
bool isPath = false);
/**
* Perform a case-independent string comparison
*/
static int Strucmp(const char* s1, const char* s2);
/**
* Split a string on its newlines into multiple lines
* Return false only if the last line stored had no newline
*/
static bool Split(const std::string& s, std::vector<std::string>& l);
static bool Split(const std::string& s, std::vector<std::string>& l,
char separator);
/**
* Return string with space added between capitalized words
* (i.e. EatMyShorts becomes Eat My Shorts )
* (note that IEatShorts becomes IEat Shorts)
*/
static std::string AddSpaceBetweenCapitalizedWords(const std::string&);
/**
* Append two or more strings and produce new one.
* Programmer must 'delete []' the resulting string, which was allocated
* with 'new'.
* Return 0 if inputs are empty or there was an error
*/
static char* AppendStrings(const char* str1, const char* str2);
static char* AppendStrings(const char* str1, const char* str2,
const char* str3);
/**
* Estimate the length of the string that will be produced
* from printing the given format string and arguments. The
* returned length will always be at least as large as the string
* that will result from printing.
* WARNING: since va_arg is called to iterate of the argument list,
* you will not be able to use this 'ap' anymore from the beginning.
* It's up to you to call va_end though.
*/
static int EstimateFormatLength(const char* format, va_list ap);
/**
* Escape specific characters in 'str'.
*/
static std::string EscapeChars(const char* str, const char* chars_to_escape,
char escape_char = '\\');
/** -----------------------------------------------------------------
* Filename Manipulation Routines
* -----------------------------------------------------------------
*/
/**
* Replace Windows file system slashes with Unix-style slashes.
*/
static void ConvertToUnixSlashes(std::string& path);
#ifdef _WIN32
/** Calls Encoding::ToWindowsExtendedPath. */
static std::wstring ConvertToWindowsExtendedPath(const std::string&);
#endif
/**
* For windows this calls ConvertToWindowsOutputPath and for unix
* it calls ConvertToUnixOutputPath
*/
static std::string ConvertToOutputPath(const std::string&);
/**
* Convert the path to a string that can be used in a unix makefile.
* double slashes are removed, and spaces are escaped.
*/
static std::string ConvertToUnixOutputPath(const std::string&);
/**
* Convert the path to string that can be used in a windows project or
* makefile. Double slashes are removed if they are not at the start of
* the string, the slashes are converted to windows style backslashes, and
* if there are spaces in the string it is double quoted.
*/
static std::string ConvertToWindowsOutputPath(const std::string&);
/**
* Return true if a path with the given name exists in the current directory.
*/
static bool PathExists(const std::string& path);
/**
* Return true if a file exists in the current directory.
* If isFile = true, then make sure the file is a file and
* not a directory. If isFile = false, then return true
* if it is a file or a directory. Note that the file will
* also be checked for read access. (Currently, this check
* for read access is only done on POSIX systems.)
*/
static bool FileExists(const char* filename, bool isFile);
static bool FileExists(const std::string& filename, bool isFile);
static bool FileExists(const char* filename);
static bool FileExists(const std::string& filename);
/**
* Test if a file exists and can be accessed with the requested
* permissions. Symbolic links are followed. Returns true if
* the access test was successful.
*
* On POSIX systems (including Cygwin), this maps to the access
* function. On Windows systems, all existing files are
* considered readable, and writable files are considered to
* have the read-only file attribute cleared.
*/
static bool TestFileAccess(const char* filename,
TestFilePermissions permissions);
static bool TestFileAccess(const std::string& filename,
TestFilePermissions permissions);
/**
* Cross platform wrapper for stat struct
*/
#if defined(_WIN32) && !defined(__CYGWIN__)
# if defined(__BORLANDC__)
typedef struct stati64 Stat_t;
# else
typedef struct _stat64 Stat_t;
# endif
#else
typedef struct stat Stat_t;
#endif
/**
* Cross platform wrapper for stat system call
*
* On Windows this may not work for paths longer than 250 characters
* due to limitations of the underlying '_wstat64' call.
*/
static int Stat(const char* path, Stat_t* buf);
static int Stat(const std::string& path, Stat_t* buf);
/**
* Converts Cygwin path to Win32 path. Uses dictionary container for
* caching and calls to cygwin_conv_to_win32_path from Cygwin dll
* for actual translation. Returns true on success, else false.
*/
#ifdef __CYGWIN__
static bool PathCygwinToWin32(const char* path, char* win32_path);
#endif
/**
* Return file length
*/
static unsigned long FileLength(const std::string& filename);
/**
Change the modification time or create a file
*/
static bool Touch(const std::string& filename, bool create);
/**
* Compare file modification times.
* Return true for successful comparison and false for error.
* When true is returned, result has -1, 0, +1 for
* f1 older, same, or newer than f2.
*/
static bool FileTimeCompare(const std::string& f1, const std::string& f2,
int* result);
/**
* Get the file extension (including ".") needed for an executable
* on the current platform ("" for unix, ".exe" for Windows).
*/
static const char* GetExecutableExtension();
/**
* Given a path on a Windows machine, return the actual case of
* the path as it exists on disk. Path components that do not
* exist on disk are returned unchanged. Relative paths are always
* returned unchanged. Drive letters are always made upper case.
* This does nothing on non-Windows systems but return the path.
*/
static std::string GetActualCaseForPath(const std::string& path);
/**
* Given the path to a program executable, get the directory part of
* the path with the file stripped off. If there is no directory
* part, the empty string is returned.
*/
static std::string GetProgramPath(const std::string&);
static bool SplitProgramPath(const std::string& in_name, std::string& dir,
std::string& file, bool errorReport = true);
/**
* Given argv[0] for a unix program find the full path to a running
* executable. argv0 can be null for windows WinMain programs
* in this case GetModuleFileName will be used to find the path
* to the running executable. If argv0 is not a full path,
* then this will try to find the full path. If the path is not
* found false is returned, if found true is returned. An error
* message of the attempted paths is stored in errorMsg.
* exeName is the name of the executable.
* buildDir is a possibly null path to the build directory.
* installPrefix is a possibly null pointer to the install directory.
*/
static bool FindProgramPath(const char* argv0, std::string& pathOut,
std::string& errorMsg,
const char* exeName = nullptr,
const char* buildDir = nullptr,
const char* installPrefix = nullptr);
/**
* Given a path to a file or directory, convert it to a full path.
* This collapses away relative paths relative to the cwd argument
* (which defaults to the current working directory). The full path
* is returned.
*/
static std::string CollapseFullPath(const std::string& in_relative);
static std::string CollapseFullPath(const std::string& in_relative,
const char* in_base);
static std::string CollapseFullPath(const std::string& in_relative,
const std::string& in_base);
/**
* Get the real path for a given path, removing all symlinks. In
* the event of an error (non-existent path, permissions issue,
* etc.) the original path is returned if errorMessage pointer is
* nullptr. Otherwise empty string is returned and errorMessage
* contains error description.
*/
static std::string GetRealPath(const std::string& path,
std::string* errorMessage = nullptr);
/**
* Split a path name into its root component and the rest of the
* path. The root component is one of the following:
* "/" = UNIX full path
* "c:/" = Windows full path (can be any drive letter)
* "c:" = Windows drive-letter relative path (can be any drive letter)
* "//" = Network path
* "~/" = Home path for current user
* "~u/" = Home path for user 'u'
* "" = Relative path
*
* A pointer to the rest of the path after the root component is
* returned. The root component is stored in the "root" string if
* given.
*/
static const char* SplitPathRootComponent(const std::string& p,
std::string* root = nullptr);
/**
* 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.
*
* This does *not* normalize the input path. All components are
* preserved, including empty ones. Typically callers should use
* this only on paths that have already been normalized.
*/
static void SplitPath(const std::string& p,
std::vector<std::string>& components,
bool expand_home_dir = true);
/**
* Join components of a path name into a single string. See
* SplitPath for the format of the components.
*
* This does *not* normalize the input path. All components are
* preserved, including empty ones. Typically callers should use
* this only on paths that have already been normalized.
*/
static std::string JoinPath(const std::vector<std::string>& components);
static std::string JoinPath(std::vector<std::string>::const_iterator first,
std::vector<std::string>::const_iterator last);
/**
* Compare a path or components of a path.
*/
static bool ComparePath(const std::string& c1, const std::string& c2);
/**
* Return path of a full filename (no trailing slashes)
*/
static std::string GetFilenamePath(const std::string&);
/**
* Return file name of a full filename (i.e. file name without path)
*/
static std::string GetFilenameName(const std::string&);
/**
* Return longest file extension of a full filename (dot included)
*/
static std::string GetFilenameExtension(const std::string&);
/**
* Return shortest file extension of a full filename (dot included)
*/
static std::string GetFilenameLastExtension(const std::string& filename);
/**
* Return file name without extension of a full filename
*/
static std::string GetFilenameWithoutExtension(const std::string&);
/**
* Return file name without its last (shortest) extension
*/
static std::string GetFilenameWithoutLastExtension(const std::string&);
/**
* Return whether the path represents a full path (not relative)
*/
static bool FileIsFullPath(const std::string&);
static bool FileIsFullPath(const char*);
/**
* For windows return the short path for the given path,
* Unix just a pass through
*/
static bool GetShortPath(const std::string& path, std::string& result);
/**
* Read line from file. Make sure to read a full line and truncates it if
* requested via sizeLimit. Returns true if any data were read before the
* end-of-file was reached. If the has_newline argument is specified, it will
* be true when the line read had a newline character.
*/
static bool GetLineFromStream(std::istream& istr, std::string& line,
bool* has_newline = nullptr,
long sizeLimit = -1);
/**
* Get the parent directory of the directory or file
*/
static std::string GetParentDirectory(const std::string& fileOrDir);
/**
* Check if the given file or directory is in subdirectory of dir
*/
static bool IsSubDirectory(const std::string& fileOrDir,
const std::string& dir);
/** -----------------------------------------------------------------
* File Manipulation Routines
* -----------------------------------------------------------------
*/
/**
* Open a file considering unicode.
*/
static FILE* Fopen(const std::string& file, const char* mode);
/**
* Visual C++ does not define mode_t (note that Borland does, however).
*/
#if defined(_MSC_VER)
typedef unsigned short mode_t;
#endif
/**
* 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, const mode_t* mode = nullptr);
static bool MakeDirectory(const std::string& path,
const mode_t* mode = nullptr);
/**
* Copy the source file to the destination file only
* if the two files differ.
*/
static bool CopyFileIfDifferent(const std::string& source,
const std::string& destination);
/**
* Compare the contents of two files. Return true if different
*/
static bool FilesDiffer(const std::string& source,
const std::string& destination);
/**
* Compare the contents of two files, ignoring line ending differences.
* Return true if different
*/
static bool TextFilesDiffer(const std::string& path1,
const std::string& path2);
/**
* Return true if the two files are the same file
*/
static bool SameFile(const std::string& file1, const std::string& file2);
/**
* Copy a file.
*/
static bool CopyFileAlways(const std::string& source,
const std::string& destination);
/**
* Copy a file. If the "always" argument is true the file is always
* copied. If it is false, the file is copied only if it is new or
* has changed.
*/
static bool CopyAFile(const std::string& source,
const std::string& destination, bool always = true);
/**
* Copy content directory to another directory with all files and
* subdirectories. If the "always" argument is true all files are
* always copied. If it is false, only files that have changed or
* are new are copied.
*/
static bool CopyADirectory(const std::string& source,
const std::string& destination,
bool always = true);
/**
* Remove a file
*/
static bool RemoveFile(const std::string& source);
/**
* Remove a directory
*/
static bool RemoveADirectory(const std::string& source);
/**
* Get the maximum full file path length
*/
static size_t GetMaximumFilePathLength();
/**
* Find a file in the system PATH, with optional extra paths
*/
static std::string FindFile(
const std::string& name,
const std::vector<std::string>& path = std::vector<std::string>(),
bool no_system_path = false);
/**
* Find a directory in the system PATH, with optional extra paths
*/
static std::string FindDirectory(
const std::string& name,
const std::vector<std::string>& path = std::vector<std::string>(),
bool no_system_path = false);
/**
* Find an executable in the system PATH, with optional extra paths
*/
static std::string FindProgram(
const char* name,
const std::vector<std::string>& path = std::vector<std::string>(),
bool no_system_path = false);
static std::string FindProgram(
const std::string& name,
const std::vector<std::string>& path = std::vector<std::string>(),
bool no_system_path = false);
static std::string FindProgram(
const std::vector<std::string>& names,
const std::vector<std::string>& path = std::vector<std::string>(),
bool no_system_path = false);
/**
* Find a library in the system PATH, with optional extra paths
*/
static std::string FindLibrary(const std::string& name,
const std::vector<std::string>& path);
/**
* Return true if the file is a directory
*/
static bool FileIsDirectory(const std::string& name);
/**
* Return true if the file is a symlink
*/
static bool FileIsSymlink(const std::string& name);
/**
* Return true if the file is a FIFO
*/
static bool FileIsFIFO(const std::string& name);
/**
* Return true if the file has a given signature (first set of bytes)
*/
static bool FileHasSignature(const char* filename, const char* signature,
long offset = 0);
/**
* Attempt to detect and return the type of a file.
* Up to 'length' bytes are read from the file, if more than 'percent_bin' %
* of the bytes are non-textual elements, the file is considered binary,
* otherwise textual. Textual elements are bytes in the ASCII [0x20, 0x7E]
* range, but also \\n, \\r, \\t.
* The algorithm is simplistic, and should probably check for usual file
* extensions, 'magic' signature, unicode, etc.
*/
enum FileTypeEnum
{
FileTypeUnknown,
FileTypeBinary,
FileTypeText
};
static SystemTools::FileTypeEnum DetectFileType(const char* filename,
unsigned long length = 256,
double percent_bin = 0.05);
/**
* Create a symbolic link if the platform supports it. Returns whether
* creation succeeded.
*/
static bool CreateSymlink(const std::string& origName,
const std::string& newName);
/**
* Read the contents of a symbolic link. Returns whether reading
* succeeded.
*/
static bool ReadSymlink(const std::string& newName, std::string& origName);
/**
* Try to locate the file 'filename' in the directory 'dir'.
* If 'filename' is a fully qualified filename, the basename of the file is
* used to check for its existence in 'dir'.
* If 'dir' is not a directory, GetFilenamePath() is called on 'dir' to
* get its directory first (thus, you can pass a filename as 'dir', as
* a convenience).
* 'filename_found' is assigned the fully qualified name/path of the file
* if it is found (not touched otherwise).
* If 'try_filename_dirs' is true, try to find the file using the
* components of its path, i.e. if we are looking for c:/foo/bar/bill.txt,
* first look for bill.txt in 'dir', then in 'dir'/bar, then in 'dir'/foo/bar
* etc.
* Return true if the file was found, false otherwise.
*/
static bool LocateFileInDir(const char* filename, const char* dir,
std::string& filename_found,
int try_filename_dirs = 0);
/** compute the relative path from local to remote. local must
be a directory. remote can be a file or a directory.
Both remote and local must be full paths. Basically, if
you are in directory local and you want to access the file in remote
what is the relative path to do that. For example:
/a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
*/
static std::string RelativePath(const std::string& local,
const std::string& remote);
/**
* Return file's modified time
*/
static long int ModifiedTime(const std::string& filename);
/**
* Return file's creation time (Win32: works only for NTFS, not FAT)
*/
static long int CreationTime(const std::string& filename);
/**
* Get and set permissions of the file. If honor_umask is set, the umask
* is queried and applied to the given permissions. Returns false if
* failure.
*
* WARNING: A non-thread-safe method is currently used to get the umask
* if a honor_umask parameter is set to true.
*/
static bool GetPermissions(const char* file, mode_t& mode);
static bool GetPermissions(const std::string& file, mode_t& mode);
static bool SetPermissions(const char* file, mode_t mode,
bool honor_umask = false);
static bool SetPermissions(const std::string& file, mode_t mode,
bool honor_umask = false);
/** -----------------------------------------------------------------
* Time Manipulation Routines
* -----------------------------------------------------------------
*/
/** Get current time in seconds since Posix Epoch (Jan 1, 1970). */
static double GetTime();
/**
* Get current date/time
*/
static std::string GetCurrentDateTime(const char* format);
/** -----------------------------------------------------------------
* Registry Manipulation Routines
* -----------------------------------------------------------------
*/
/**
* Specify access to the 32-bit or 64-bit application view of
* registry values. The default is to match the currently running
* binary type.
*/
enum KeyWOW64
{
KeyWOW64_Default,
KeyWOW64_32,
KeyWOW64_64
};
/**
* Get a list of subkeys.
*/
static bool GetRegistrySubKeys(const std::string& key,
std::vector<std::string>& subkeys,
KeyWOW64 view = KeyWOW64_Default);
/**
* Read a registry value
*/
static bool ReadRegistryValue(const std::string& key, std::string& value,
KeyWOW64 view = KeyWOW64_Default);
/**
* Write a registry value
*/
static bool WriteRegistryValue(const std::string& key,
const std::string& value,
KeyWOW64 view = KeyWOW64_Default);
/**
* Delete a registry value
*/
static bool DeleteRegistryValue(const std::string& key,
KeyWOW64 view = KeyWOW64_Default);
/** -----------------------------------------------------------------
* Environment Manipulation Routines
* -----------------------------------------------------------------
*/
/**
* Add the paths from the environment variable PATH to the
* string vector passed in. If env is set then the value
* of env will be used instead of PATH.
*/
static void GetPath(std::vector<std::string>& path,
const char* env = nullptr);
/**
* Read an environment variable
*/
static const char* GetEnv(const char* key);
static const char* GetEnv(const std::string& key);
static bool GetEnv(const char* key, std::string& result);
static bool GetEnv(const std::string& key, std::string& result);
static bool HasEnv(const char* key);
static bool HasEnv(const std::string& key);
/** Put a string into the environment
of the form var=value */
static bool PutEnv(const std::string& env);
/** Remove a string from the environment.
Input is of the form "var" or "var=value" (value is ignored). */
static bool UnPutEnv(const std::string& env);
/**
* Get current working directory CWD
*/
static std::string GetCurrentWorkingDirectory(bool collapse = true);
/**
* Change directory to the directory specified
*/
static int ChangeDirectory(const std::string& dir);
/**
* Get the result of strerror(errno)
*/
static std::string GetLastSystemError();
/**
* When building DEBUG with MSVC, this enables a hook that prevents
* error dialogs from popping up if the program is being run from
* DART.
*/
static void EnableMSVCDebugHook();
/**
* Get the width of the terminal window. The code may or may not work, so
* make sure you have some reasonable defaults prepared if the code returns
* some bogus size.
*/
static int GetTerminalWidth();
#if @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP
/**
* Add an entry in the path translation table.
*/
static void AddTranslationPath(const std::string& dir,
const std::string& refdir);
/**
* If dir is different after CollapseFullPath is called,
* Then insert it into the path translation table
*/
static void AddKeepPath(const std::string& dir);
/**
* Update path by going through the Path Translation table;
*/
static void CheckTranslationPath(std::string& path);
#endif
/**
* Delay the execution for a specified amount of time specified
* in milliseconds
*/
static void Delay(unsigned int msec);
/**
* Get the operating system name and version
* This is implemented for Win32 only for the moment
*/
static std::string GetOperatingSystemNameAndVersion();
/** -----------------------------------------------------------------
* URL Manipulation Routines
* -----------------------------------------------------------------
*/
/**
* Parse a character string :
* protocol://dataglom
* and fill protocol as appropriate.
* Return false if the URL does not have the required form, true otherwise.
*/
static bool ParseURLProtocol(const std::string& URL, std::string& protocol,
std::string& dataglom);
/**
* Parse a string (a URL without protocol prefix) with the form:
* protocol://[[username[':'password]'@']hostname[':'dataport]]'/'[datapath]
* and fill protocol, username, password, hostname, dataport, and datapath
* when values are found.
* Return true if the string matches the format; false otherwise.
*/
static bool ParseURL(const std::string& URL, std::string& protocol,
std::string& username, std::string& password,
std::string& hostname, std::string& dataport,
std::string& datapath);
private:
/**
* Allocate the stl map that serve as the Path Translation table.
*/
static void ClassInitialize();
/**
* Deallocate the stl map that serve as the Path Translation table.
*/
static void ClassFinalize();
/**
* This method prevents warning on SGI
*/
SystemToolsManager* GetSystemToolsManager()
{
return &SystemToolsManagerInstance;
}
static SystemToolsStatic* Statics;
friend class SystemToolsStatic;
friend class SystemToolsManager;
};
} // namespace @KWSYS_NAMESPACE@
#endif
-414
View File
@@ -1,414 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Terminal.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
#if 0
# include "Terminal.h.in"
#endif
/* Configure support for this platform. */
#if defined(_WIN32) || defined(__CYGWIN__)
# define KWSYS_TERMINAL_SUPPORT_CONSOLE
#endif
#if !defined(_WIN32)
# define KWSYS_TERMINAL_ISATTY_WORKS
#endif
/* Include needed system APIs. */
#include <stdarg.h> /* va_list */
#include <stdlib.h> /* getenv */
#include <string.h> /* strcmp */
#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
# include <io.h> /* _get_osfhandle */
# include <windows.h> /* SetConsoleTextAttribute */
#endif
#if defined(KWSYS_TERMINAL_ISATTY_WORKS)
# include <unistd.h> /* isatty */
#else
# include <sys/stat.h> /* fstat */
#endif
static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100,
int default_tty);
static void kwsysTerminalSetVT100Color(FILE* stream, int color);
#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
static HANDLE kwsysTerminalGetStreamHandle(FILE* stream);
static void kwsysTerminalSetConsoleColor(HANDLE hOut,
CONSOLE_SCREEN_BUFFER_INFO* hOutInfo,
FILE* stream, int color);
#endif
void kwsysTerminal_cfprintf(int color, FILE* stream, const char* format, ...)
{
/* Setup the stream with the given color if possible. */
int pipeIsConsole = 0;
int pipeIsVT100 = 0;
int default_vt100 = color & kwsysTerminal_Color_AssumeVT100;
int default_tty = color & kwsysTerminal_Color_AssumeTTY;
#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
HANDLE hOut = kwsysTerminalGetStreamHandle(stream);
if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) {
pipeIsConsole = 1;
kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, color);
}
#endif
if (!pipeIsConsole &&
kwsysTerminalStreamIsVT100(stream, default_vt100, default_tty)) {
pipeIsVT100 = 1;
kwsysTerminalSetVT100Color(stream, color);
}
/* Format the text into the stream. */
{
va_list var_args;
va_start(var_args, format);
vfprintf(stream, format, var_args);
va_end(var_args);
}
/* Restore the normal color state for the stream. */
#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
if (pipeIsConsole) {
kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream,
kwsysTerminal_Color_Normal);
}
#endif
if (pipeIsVT100) {
kwsysTerminalSetVT100Color(stream, kwsysTerminal_Color_Normal);
}
}
/* Detect cases when a stream is definitely not interactive. */
#if !defined(KWSYS_TERMINAL_ISATTY_WORKS)
static int kwsysTerminalStreamIsNotInteractive(FILE* stream)
{
/* The given stream is definitely not interactive if it is a regular
file. */
struct stat stream_stat;
if (fstat(fileno(stream), &stream_stat) == 0) {
if (stream_stat.st_mode & S_IFREG) {
return 1;
}
}
return 0;
}
#endif
/* List of terminal names known to support VT100 color escape sequences. */
static const char* kwsysTerminalVT100Names[] = { "Eterm",
"alacritty",
"alacritty-direct",
"ansi",
"color-xterm",
"con132x25",
"con132x30",
"con132x43",
"con132x60",
"con80x25",
"con80x28",
"con80x30",
"con80x43",
"con80x50",
"con80x60",
"cons25",
"console",
"cygwin",
"dtterm",
"eterm-color",
"gnome",
"gnome-256color",
"konsole",
"konsole-256color",
"kterm",
"linux",
"msys",
"linux-c",
"mach-color",
"mlterm",
"putty",
"putty-256color",
"rxvt",
"rxvt-256color",
"rxvt-cygwin",
"rxvt-cygwin-native",
"rxvt-unicode",
"rxvt-unicode-256color",
"screen",
"screen-256color",
"screen-256color-bce",
"screen-bce",
"screen-w",
"screen.linux",
"tmux",
"tmux-256color",
"vt100",
"xterm",
"xterm-16color",
"xterm-256color",
"xterm-88color",
"xterm-color",
"xterm-debian",
"xterm-kitty",
"xterm-termite",
0 };
/* Detect whether a stream is displayed in a VT100-compatible terminal. */
static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100,
int default_tty)
{
/* Force color according to http://bixense.com/clicolors/ convention. */
{
const char* clicolor_force = getenv("CLICOLOR_FORCE");
if (clicolor_force && *clicolor_force &&
strcmp(clicolor_force, "0") != 0) {
return 1;
}
}
/* If running inside emacs the terminal is not VT100. Some emacs
seem to claim the TERM is xterm even though they do not support
VT100 escapes. */
{
const char* emacs = getenv("EMACS");
if (emacs && *emacs == 't') {
return 0;
}
}
/* Check for a valid terminal. */
if (!default_vt100) {
const char** t = 0;
const char* term = getenv("TERM");
if (term) {
for (t = kwsysTerminalVT100Names; *t && strcmp(term, *t) != 0; ++t) {
}
}
if (!(t && *t)) {
return 0;
}
}
#if defined(KWSYS_TERMINAL_ISATTY_WORKS)
/* Make sure the stream is a tty. */
(void)default_tty;
return isatty(fileno(stream)) ? 1 : 0;
#else
/* Check for cases in which the stream is definitely not a tty. */
if (kwsysTerminalStreamIsNotInteractive(stream)) {
return 0;
}
/* Use the provided default for whether this is a tty. */
return default_tty;
#endif
}
/* VT100 escape sequence strings. */
#if defined(__MVS__)
/* if building on z/OS (aka MVS), assume we are using EBCDIC */
# define ESCAPE_CHAR "\47"
#else
# define ESCAPE_CHAR "\33"
#endif
#define KWSYS_TERMINAL_VT100_NORMAL ESCAPE_CHAR "[0m"
#define KWSYS_TERMINAL_VT100_BOLD ESCAPE_CHAR "[1m"
#define KWSYS_TERMINAL_VT100_UNDERLINE ESCAPE_CHAR "[4m"
#define KWSYS_TERMINAL_VT100_BLINK ESCAPE_CHAR "[5m"
#define KWSYS_TERMINAL_VT100_INVERSE ESCAPE_CHAR "[7m"
#define KWSYS_TERMINAL_VT100_FOREGROUND_BLACK ESCAPE_CHAR "[30m"
#define KWSYS_TERMINAL_VT100_FOREGROUND_RED ESCAPE_CHAR "[31m"
#define KWSYS_TERMINAL_VT100_FOREGROUND_GREEN ESCAPE_CHAR "[32m"
#define KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW ESCAPE_CHAR "[33m"
#define KWSYS_TERMINAL_VT100_FOREGROUND_BLUE ESCAPE_CHAR "[34m"
#define KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA ESCAPE_CHAR "[35m"
#define KWSYS_TERMINAL_VT100_FOREGROUND_CYAN ESCAPE_CHAR "[36m"
#define KWSYS_TERMINAL_VT100_FOREGROUND_WHITE ESCAPE_CHAR "[37m"
#define KWSYS_TERMINAL_VT100_BACKGROUND_BLACK ESCAPE_CHAR "[40m"
#define KWSYS_TERMINAL_VT100_BACKGROUND_RED ESCAPE_CHAR "[41m"
#define KWSYS_TERMINAL_VT100_BACKGROUND_GREEN ESCAPE_CHAR "[42m"
#define KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW ESCAPE_CHAR "[43m"
#define KWSYS_TERMINAL_VT100_BACKGROUND_BLUE ESCAPE_CHAR "[44m"
#define KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA ESCAPE_CHAR "[45m"
#define KWSYS_TERMINAL_VT100_BACKGROUND_CYAN ESCAPE_CHAR "[46m"
#define KWSYS_TERMINAL_VT100_BACKGROUND_WHITE ESCAPE_CHAR "[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
-170
View File
@@ -1,170 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef @KWSYS_NAMESPACE@_Terminal_h
#define @KWSYS_NAMESPACE@_Terminal_h
#include <@KWSYS_NAMESPACE@/Configure.h>
#include <stdio.h> /* For file stream type FILE. */
/* Redefine all public interface symbol names to be in the proper
namespace. These macros are used internally to kwsys only, and are
not visible to user code. Use kwsysHeaderDump.pl to reproduce
these macros after making changes to the interface. */
#if !defined(KWSYS_NAMESPACE)
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# define kwsysTerminal_cfprintf kwsys_ns(Terminal_cfprintf)
# define kwsysTerminal_Color_e kwsys_ns(Terminal_Color_e)
# define kwsysTerminal_Color_Normal kwsys_ns(Terminal_Color_Normal)
# define kwsysTerminal_Color_ForegroundBlack \
kwsys_ns(Terminal_Color_ForegroundBlack)
# define kwsysTerminal_Color_ForegroundRed \
kwsys_ns(Terminal_Color_ForegroundRed)
# define kwsysTerminal_Color_ForegroundGreen \
kwsys_ns(Terminal_Color_ForegroundGreen)
# define kwsysTerminal_Color_ForegroundYellow \
kwsys_ns(Terminal_Color_ForegroundYellow)
# define kwsysTerminal_Color_ForegroundBlue \
kwsys_ns(Terminal_Color_ForegroundBlue)
# define kwsysTerminal_Color_ForegroundMagenta \
kwsys_ns(Terminal_Color_ForegroundMagenta)
# define kwsysTerminal_Color_ForegroundCyan \
kwsys_ns(Terminal_Color_ForegroundCyan)
# define kwsysTerminal_Color_ForegroundWhite \
kwsys_ns(Terminal_Color_ForegroundWhite)
# define kwsysTerminal_Color_ForegroundMask \
kwsys_ns(Terminal_Color_ForegroundMask)
# define kwsysTerminal_Color_BackgroundBlack \
kwsys_ns(Terminal_Color_BackgroundBlack)
# define kwsysTerminal_Color_BackgroundRed \
kwsys_ns(Terminal_Color_BackgroundRed)
# define kwsysTerminal_Color_BackgroundGreen \
kwsys_ns(Terminal_Color_BackgroundGreen)
# define kwsysTerminal_Color_BackgroundYellow \
kwsys_ns(Terminal_Color_BackgroundYellow)
# define kwsysTerminal_Color_BackgroundBlue \
kwsys_ns(Terminal_Color_BackgroundBlue)
# define kwsysTerminal_Color_BackgroundMagenta \
kwsys_ns(Terminal_Color_BackgroundMagenta)
# define kwsysTerminal_Color_BackgroundCyan \
kwsys_ns(Terminal_Color_BackgroundCyan)
# define kwsysTerminal_Color_BackgroundWhite \
kwsys_ns(Terminal_Color_BackgroundWhite)
# define kwsysTerminal_Color_BackgroundMask \
kwsys_ns(Terminal_Color_BackgroundMask)
# define kwsysTerminal_Color_ForegroundBold \
kwsys_ns(Terminal_Color_ForegroundBold)
# define kwsysTerminal_Color_BackgroundBold \
kwsys_ns(Terminal_Color_BackgroundBold)
# define kwsysTerminal_Color_AssumeTTY kwsys_ns(Terminal_Color_AssumeTTY)
# define kwsysTerminal_Color_AssumeVT100 kwsys_ns(Terminal_Color_AssumeVT100)
# define kwsysTerminal_Color_AttributeMask \
kwsys_ns(Terminal_Color_AttributeMask)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/**
* Write colored and formatted text to a stream. Color is used only
* for streams supporting it. The color specification is constructed
* by bitwise-OR-ing enumeration values. At most one foreground and
* one background value may be given.
*
* Whether the a stream supports color is usually automatically
* detected, but with two exceptions:
*
* - When the stream is displayed in a terminal supporting VT100
* color but using an intermediate pipe for communication the
* detection of a tty fails. (This typically occurs for a shell
* running in an rxvt terminal in MSYS.) If the caller knows this
* to be the case, the attribute Color_AssumeTTY may be included in
* the color specification.
*
* - When the stream is displayed in a terminal whose TERM
* environment variable is not set or is set to a value that is not
* known to support VT100 colors. If the caller knows this to be
* the case, the attribute Color_AssumeVT100 may be included in the
* color specification.
*/
kwsysEXPORT void kwsysTerminal_cfprintf(int color, FILE* stream,
const char* format, ...);
enum kwsysTerminal_Color_e
{
/* Normal Text */
kwsysTerminal_Color_Normal = 0,
/* Foreground Color */
kwsysTerminal_Color_ForegroundBlack = 0x1,
kwsysTerminal_Color_ForegroundRed = 0x2,
kwsysTerminal_Color_ForegroundGreen = 0x3,
kwsysTerminal_Color_ForegroundYellow = 0x4,
kwsysTerminal_Color_ForegroundBlue = 0x5,
kwsysTerminal_Color_ForegroundMagenta = 0x6,
kwsysTerminal_Color_ForegroundCyan = 0x7,
kwsysTerminal_Color_ForegroundWhite = 0x8,
kwsysTerminal_Color_ForegroundMask = 0xF,
/* Background Color */
kwsysTerminal_Color_BackgroundBlack = 0x10,
kwsysTerminal_Color_BackgroundRed = 0x20,
kwsysTerminal_Color_BackgroundGreen = 0x30,
kwsysTerminal_Color_BackgroundYellow = 0x40,
kwsysTerminal_Color_BackgroundBlue = 0x50,
kwsysTerminal_Color_BackgroundMagenta = 0x60,
kwsysTerminal_Color_BackgroundCyan = 0x70,
kwsysTerminal_Color_BackgroundWhite = 0x80,
kwsysTerminal_Color_BackgroundMask = 0xF0,
/* Attributes */
kwsysTerminal_Color_ForegroundBold = 0x100,
kwsysTerminal_Color_BackgroundBold = 0x200,
kwsysTerminal_Color_AssumeTTY = 0x400,
kwsysTerminal_Color_AssumeVT100 = 0x800,
kwsysTerminal_Color_AttributeMask = 0xF00
};
#if defined(__cplusplus)
} /* extern "C" */
#endif
/* If we are building a kwsys .c or .cxx file, let it use these macros.
Otherwise, undefine them to keep the namespace clean. */
#if !defined(KWSYS_NAMESPACE)
# undef kwsys_ns
# undef kwsysEXPORT
# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
# undef kwsysTerminal_cfprintf
# undef kwsysTerminal_Color_e
# undef kwsysTerminal_Color_Normal
# undef kwsysTerminal_Color_ForegroundBlack
# undef kwsysTerminal_Color_ForegroundRed
# undef kwsysTerminal_Color_ForegroundGreen
# undef kwsysTerminal_Color_ForegroundYellow
# undef kwsysTerminal_Color_ForegroundBlue
# undef kwsysTerminal_Color_ForegroundMagenta
# undef kwsysTerminal_Color_ForegroundCyan
# undef kwsysTerminal_Color_ForegroundWhite
# undef kwsysTerminal_Color_ForegroundMask
# undef kwsysTerminal_Color_BackgroundBlack
# undef kwsysTerminal_Color_BackgroundRed
# undef kwsysTerminal_Color_BackgroundGreen
# undef kwsysTerminal_Color_BackgroundYellow
# undef kwsysTerminal_Color_BackgroundBlue
# undef kwsysTerminal_Color_BackgroundMagenta
# undef kwsysTerminal_Color_BackgroundCyan
# undef kwsysTerminal_Color_BackgroundWhite
# undef kwsysTerminal_Color_BackgroundMask
# undef kwsysTerminal_Color_ForegroundBold
# undef kwsysTerminal_Color_BackgroundBold
# undef kwsysTerminal_Color_AssumeTTY
# undef kwsysTerminal_Color_AssumeVT100
# undef kwsysTerminal_Color_AttributeMask
# endif
#endif
#endif
-128
View File
@@ -1,128 +0,0 @@
#!/usr/bin/env bash
#=============================================================================
# Copyright 2015-2017 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
usage='usage: clang-format.bash [<options>] [--]
--help Print usage plus more detailed help.
--clang-format <tool> Use given clang-format tool.
--amend Filter files changed by HEAD.
--cached Filter files locally staged for commit.
--modified Filter files locally modified from HEAD.
--tracked Filter files tracked by Git.
'
help="$usage"'
Example to format locally modified files:
./clang-format.bash --modified
Example to format locally modified files staged for commit:
./clang-format.bash --cached
Example to format files modified by the most recent commit:
./clang-format.bash --amend
Example to format all files:
./clang-format.bash --tracked
Example to format the current topic:
git filter-branch \
--tree-filter "./clang-format.bash --tracked" \
master..
'
die() {
echo "$@" 1>&2; exit 1
}
#-----------------------------------------------------------------------------
# Parse command-line arguments.
clang_format=''
mode=''
while test "$#" != 0; do
case "$1" in
--amend) mode="amend" ;;
--cached) mode="cached" ;;
--clang-format) shift; clang_format="$1" ;;
--help) echo "$help"; exit 0 ;;
--modified) mode="modified" ;;
--tracked) mode="tracked" ;;
--) shift ; break ;;
-*) die "$usage" ;;
*) break ;;
esac
shift
done
test "$#" = 0 || die "$usage"
# Find a default tool.
tools='
clang-format-6.0
clang-format
'
if test "x$clang_format" = "x"; then
for tool in $tools; do
if type -p "$tool" >/dev/null; then
clang_format="$tool"
break
fi
done
fi
# Verify that we have a tool.
if ! type -p "$clang_format" >/dev/null; then
echo "Unable to locate a 'clang-format' tool."
exit 1
fi
if ! "$clang_format" --version | grep 'clang-format version 6\.0' >/dev/null 2>/dev/null; then
echo "clang-format version 6.0 is required (exactly)"
exit 1
fi
# Select listing mode.
case "$mode" in
'') echo "$usage"; exit 0 ;;
amend) git_ls='git diff-tree --diff-filter=AM --name-only HEAD -r --no-commit-id' ;;
cached) git_ls='git diff-index --diff-filter=AM --name-only HEAD --cached' ;;
modified) git_ls='git diff-index --diff-filter=AM --name-only HEAD' ;;
tracked) git_ls='git ls-files' ;;
*) die "invalid mode: $mode" ;;
esac
# List files as selected above.
list_files() {
$git_ls |
# Select sources with our attribute.
git check-attr --stdin format.clang-format |
sed -n '/: format\.clang-format: set$/ {s/:[^:]*:[^:]*$//p}'
}
# Transform configured sources to protect @SYMBOLS@.
list_files | xargs -d '\n' sed -i 's/@\(KWSYS_[A-Z0-9_]\+\)@/x\1x/g'
# Update sources in-place.
list_files | xargs -d '\n' "$clang_format" -i
# Transform configured sources to restore @SYMBOLS@.
list_files | xargs -d '\n' sed -i 's/x\(KWSYS_[A-Z0-9_]\+\)x/@\1@/g'
-166
View File
@@ -1,166 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
/*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
#ifndef @KWSYS_NAMESPACE@_hash_fun_hxx
#define @KWSYS_NAMESPACE@_hash_fun_hxx
#include <@KWSYS_NAMESPACE@/Configure.hxx>
#include <stddef.h> // size_t
#include <string>
namespace @KWSYS_NAMESPACE@ {
template <class _Key>
struct hash
{
};
inline size_t _stl_hash_string(const char* __s)
{
unsigned long __h = 0;
for (; *__s; ++__s)
__h = 5 * __h + *__s;
return size_t(__h);
}
template <>
struct hash<char*>
{
size_t operator()(const char* __s) const { return _stl_hash_string(__s); }
};
template <>
struct hash<const char*>
{
size_t operator()(const char* __s) const { return _stl_hash_string(__s); }
};
template <>
struct hash<std::string>
{
size_t operator()(const std::string& __s) const
{
return _stl_hash_string(__s.c_str());
}
};
#if !defined(__BORLANDC__)
template <>
struct hash<const std::string>
{
size_t operator()(const std::string& __s) const
{
return _stl_hash_string(__s.c_str());
}
};
#endif
template <>
struct hash<char>
{
size_t operator()(char __x) const { return __x; }
};
template <>
struct hash<unsigned char>
{
size_t operator()(unsigned char __x) const { return __x; }
};
template <>
struct hash<signed char>
{
size_t operator()(unsigned char __x) const { return __x; }
};
template <>
struct hash<short>
{
size_t operator()(short __x) const { return __x; }
};
template <>
struct hash<unsigned short>
{
size_t operator()(unsigned short __x) const { return __x; }
};
template <>
struct hash<int>
{
size_t operator()(int __x) const { return __x; }
};
template <>
struct hash<unsigned int>
{
size_t operator()(unsigned int __x) const { return __x; }
};
template <>
struct hash<long>
{
size_t operator()(long __x) const { return __x; }
};
template <>
struct hash<unsigned long>
{
size_t operator()(unsigned long __x) const { return __x; }
};
// use long long or __int64
#if @KWSYS_USE_LONG_LONG@
template <>
struct hash<long long>
{
size_t operator()(long long __x) const { return __x; }
};
template <>
struct hash<unsigned long long>
{
size_t operator()(unsigned long long __x) const { return __x; }
};
#elif @KWSYS_USE___INT64@
template <>
struct hash<__int64>
{
size_t operator()(__int64 __x) const { return __x; }
};
template <>
struct hash<unsigned __int64>
{
size_t operator()(unsigned __int64 __x) const { return __x; }
};
#endif // use long long or __int64
} // namespace @KWSYS_NAMESPACE@
#endif
-423
View File
@@ -1,423 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
/*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
#ifndef @KWSYS_NAMESPACE@_hash_map_hxx
#define @KWSYS_NAMESPACE@_hash_map_hxx
#include <@KWSYS_NAMESPACE@/hashtable.hxx>
#include <@KWSYS_NAMESPACE@/hash_fun.hxx>
#include <functional> // equal_to
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4284)
# pragma warning(disable : 4786)
#endif
#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
# pragma set woff 1174
# pragma set woff 1375
#endif
namespace @KWSYS_NAMESPACE@ {
// select1st is an extension: it is not part of the standard.
template <class T1, class T2>
struct hash_select1st
{
const T1& operator()(const std::pair<T1, T2>& __x) const
{
return __x.first;
}
};
// Forward declaration of equality operator; needed for friend declaration.
template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
class _EqualKey = std::equal_to<_Key>,
class _Alloc = std::allocator<char> >
class hash_map;
template <class _Key, class _Tp, class _HashFn, class _EqKey, class _Alloc>
bool operator==(const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&,
const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&);
template <class _Key, class _Tp, class _HashFcn, class _EqualKey, class _Alloc>
class hash_map
{
private:
typedef hashtable<std::pair<const _Key, _Tp>, _Key, _HashFcn,
hash_select1st<const _Key, _Tp>, _EqualKey, _Alloc>
_Ht;
_Ht _M_ht;
public:
typedef typename _Ht::key_type key_type;
typedef _Tp data_type;
typedef _Tp mapped_type;
typedef typename _Ht::value_type value_type;
typedef typename _Ht::hasher hasher;
typedef typename _Ht::key_equal key_equal;
typedef typename _Ht::size_type size_type;
typedef typename _Ht::difference_type difference_type;
typedef typename _Ht::pointer pointer;
typedef typename _Ht::const_pointer const_pointer;
typedef typename _Ht::reference reference;
typedef typename _Ht::const_reference const_reference;
typedef typename _Ht::iterator iterator;
typedef typename _Ht::const_iterator const_iterator;
typedef typename _Ht::allocator_type allocator_type;
hasher hash_funct() const { return _M_ht.hash_funct(); }
key_equal key_eq() const { return _M_ht.key_eq(); }
allocator_type get_allocator() const { return _M_ht.get_allocator(); }
public:
hash_map()
: _M_ht(100, hasher(), key_equal(), allocator_type())
{
}
explicit hash_map(size_type __n)
: _M_ht(__n, hasher(), key_equal(), allocator_type())
{
}
hash_map(size_type __n, const hasher& __hf)
: _M_ht(__n, __hf, key_equal(), allocator_type())
{
}
hash_map(size_type __n, const hasher& __hf, const key_equal& __eql,
const allocator_type& __a = allocator_type())
: _M_ht(__n, __hf, __eql, __a)
{
}
template <class _InputIterator>
hash_map(_InputIterator __f, _InputIterator __l)
: _M_ht(100, hasher(), key_equal(), allocator_type())
{
_M_ht.insert_unique(__f, __l);
}
template <class _InputIterator>
hash_map(_InputIterator __f, _InputIterator __l, size_type __n)
: _M_ht(__n, hasher(), key_equal(), allocator_type())
{
_M_ht.insert_unique(__f, __l);
}
template <class _InputIterator>
hash_map(_InputIterator __f, _InputIterator __l, size_type __n,
const hasher& __hf)
: _M_ht(__n, __hf, key_equal(), allocator_type())
{
_M_ht.insert_unique(__f, __l);
}
template <class _InputIterator>
hash_map(_InputIterator __f, _InputIterator __l, size_type __n,
const hasher& __hf, const key_equal& __eql,
const allocator_type& __a = allocator_type())
: _M_ht(__n, __hf, __eql, __a)
{
_M_ht.insert_unique(__f, __l);
}
public:
size_type size() const { return _M_ht.size(); }
size_type max_size() const { return _M_ht.max_size(); }
bool empty() const { return _M_ht.empty(); }
void swap(hash_map& __hs) { _M_ht.swap(__hs._M_ht); }
friend bool operator==<>(const hash_map&, const hash_map&);
iterator begin() { return _M_ht.begin(); }
iterator end() { return _M_ht.end(); }
const_iterator begin() const { return _M_ht.begin(); }
const_iterator end() const { return _M_ht.end(); }
public:
std::pair<iterator, bool> insert(const value_type& __obj)
{
return _M_ht.insert_unique(__obj);
}
template <class _InputIterator>
void insert(_InputIterator __f, _InputIterator __l)
{
_M_ht.insert_unique(__f, __l);
}
std::pair<iterator, bool> insert_noresize(const value_type& __obj)
{
return _M_ht.insert_unique_noresize(__obj);
}
iterator find(const key_type& __key) { return _M_ht.find(__key); }
const_iterator find(const key_type& __key) const
{
return _M_ht.find(__key);
}
_Tp& operator[](const key_type& __key)
{
return _M_ht.find_or_insert(value_type(__key, _Tp())).second;
}
size_type count(const key_type& __key) const { return _M_ht.count(__key); }
std::pair<iterator, iterator> equal_range(const key_type& __key)
{
return _M_ht.equal_range(__key);
}
std::pair<const_iterator, const_iterator> equal_range(
const key_type& __key) const
{
return _M_ht.equal_range(__key);
}
size_type erase(const key_type& __key) { return _M_ht.erase(__key); }
void erase(iterator __it) { _M_ht.erase(__it); }
void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
void clear() { _M_ht.clear(); }
void resize(size_type __hint) { _M_ht.resize(__hint); }
size_type bucket_count() const { return _M_ht.bucket_count(); }
size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
size_type elems_in_bucket(size_type __n) const
{
return _M_ht.elems_in_bucket(__n);
}
};
template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
bool operator==(const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1,
const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2)
{
return __hm1._M_ht == __hm2._M_ht;
}
template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
inline bool operator!=(
const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1,
const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2)
{
return !(__hm1 == __hm2);
}
template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
inline void swap(hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1,
hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2)
{
__hm1.swap(__hm2);
}
// Forward declaration of equality operator; needed for friend declaration.
template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
class _EqualKey = std::equal_to<_Key>,
class _Alloc = std::allocator<char> >
class hash_multimap;
template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1,
const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2);
template <class _Key, class _Tp, class _HashFcn, class _EqualKey, class _Alloc>
class hash_multimap
{
private:
typedef hashtable<std::pair<const _Key, _Tp>, _Key, _HashFcn,
hash_select1st<const _Key, _Tp>, _EqualKey, _Alloc>
_Ht;
_Ht _M_ht;
public:
typedef typename _Ht::key_type key_type;
typedef _Tp data_type;
typedef _Tp mapped_type;
typedef typename _Ht::value_type value_type;
typedef typename _Ht::hasher hasher;
typedef typename _Ht::key_equal key_equal;
typedef typename _Ht::size_type size_type;
typedef typename _Ht::difference_type difference_type;
typedef typename _Ht::pointer pointer;
typedef typename _Ht::const_pointer const_pointer;
typedef typename _Ht::reference reference;
typedef typename _Ht::const_reference const_reference;
typedef typename _Ht::iterator iterator;
typedef typename _Ht::const_iterator const_iterator;
typedef typename _Ht::allocator_type allocator_type;
hasher hash_funct() const { return _M_ht.hash_funct(); }
key_equal key_eq() const { return _M_ht.key_eq(); }
allocator_type get_allocator() const { return _M_ht.get_allocator(); }
public:
hash_multimap()
: _M_ht(100, hasher(), key_equal(), allocator_type())
{
}
explicit hash_multimap(size_type __n)
: _M_ht(__n, hasher(), key_equal(), allocator_type())
{
}
hash_multimap(size_type __n, const hasher& __hf)
: _M_ht(__n, __hf, key_equal(), allocator_type())
{
}
hash_multimap(size_type __n, const hasher& __hf, const key_equal& __eql,
const allocator_type& __a = allocator_type())
: _M_ht(__n, __hf, __eql, __a)
{
}
template <class _InputIterator>
hash_multimap(_InputIterator __f, _InputIterator __l)
: _M_ht(100, hasher(), key_equal(), allocator_type())
{
_M_ht.insert_equal(__f, __l);
}
template <class _InputIterator>
hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n)
: _M_ht(__n, hasher(), key_equal(), allocator_type())
{
_M_ht.insert_equal(__f, __l);
}
template <class _InputIterator>
hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n,
const hasher& __hf)
: _M_ht(__n, __hf, key_equal(), allocator_type())
{
_M_ht.insert_equal(__f, __l);
}
template <class _InputIterator>
hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n,
const hasher& __hf, const key_equal& __eql,
const allocator_type& __a = allocator_type())
: _M_ht(__n, __hf, __eql, __a)
{
_M_ht.insert_equal(__f, __l);
}
public:
size_type size() const { return _M_ht.size(); }
size_type max_size() const { return _M_ht.max_size(); }
bool empty() const { return _M_ht.empty(); }
void swap(hash_multimap& __hs) { _M_ht.swap(__hs._M_ht); }
friend bool operator==<>(const hash_multimap&, const hash_multimap&);
iterator begin() { return _M_ht.begin(); }
iterator end() { return _M_ht.end(); }
const_iterator begin() const { return _M_ht.begin(); }
const_iterator end() const { return _M_ht.end(); }
public:
iterator insert(const value_type& __obj)
{
return _M_ht.insert_equal(__obj);
}
template <class _InputIterator>
void insert(_InputIterator __f, _InputIterator __l)
{
_M_ht.insert_equal(__f, __l);
}
iterator insert_noresize(const value_type& __obj)
{
return _M_ht.insert_equal_noresize(__obj);
}
iterator find(const key_type& __key) { return _M_ht.find(__key); }
const_iterator find(const key_type& __key) const
{
return _M_ht.find(__key);
}
size_type count(const key_type& __key) const { return _M_ht.count(__key); }
std::pair<iterator, iterator> equal_range(const key_type& __key)
{
return _M_ht.equal_range(__key);
}
std::pair<const_iterator, const_iterator> equal_range(
const key_type& __key) const
{
return _M_ht.equal_range(__key);
}
size_type erase(const key_type& __key) { return _M_ht.erase(__key); }
void erase(iterator __it) { _M_ht.erase(__it); }
void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
void clear() { _M_ht.clear(); }
public:
void resize(size_type __hint) { _M_ht.resize(__hint); }
size_type bucket_count() const { return _M_ht.bucket_count(); }
size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
size_type elems_in_bucket(size_type __n) const
{
return _M_ht.elems_in_bucket(__n);
}
};
template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1,
const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2)
{
return __hm1._M_ht == __hm2._M_ht;
}
template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc>
inline bool operator!=(
const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1,
const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2)
{
return !(__hm1 == __hm2);
}
template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>
inline void swap(hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1,
hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2)
{
__hm1.swap(__hm2);
}
} // namespace @KWSYS_NAMESPACE@
#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
# pragma reset woff 1174
# pragma reset woff 1375
#endif
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif
-392
View File
@@ -1,392 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
/*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
#ifndef @KWSYS_NAMESPACE@_hash_set_hxx
#define @KWSYS_NAMESPACE@_hash_set_hxx
#include <@KWSYS_NAMESPACE@/hashtable.hxx>
#include <@KWSYS_NAMESPACE@/hash_fun.hxx>
#include <functional> // equal_to
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4284)
# pragma warning(disable : 4786)
#endif
#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
# pragma set woff 1174
# pragma set woff 1375
#endif
namespace @KWSYS_NAMESPACE@ {
// identity is an extension: it is not part of the standard.
template <class _Tp>
struct _Identity
{
const _Tp& operator()(const _Tp& __x) const { return __x; }
};
// Forward declaration of equality operator; needed for friend declaration.
template <class _Value, class _HashFcn = hash<_Value>,
class _EqualKey = std::equal_to<_Value>,
class _Alloc = std::allocator<char> >
class hash_set;
template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1,
const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2);
template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
class hash_set
{
private:
typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey,
_Alloc>
_Ht;
_Ht _M_ht;
public:
typedef typename _Ht::key_type key_type;
typedef typename _Ht::value_type value_type;
typedef typename _Ht::hasher hasher;
typedef typename _Ht::key_equal key_equal;
typedef typename _Ht::size_type size_type;
typedef typename _Ht::difference_type difference_type;
typedef typename _Ht::const_pointer pointer;
typedef typename _Ht::const_pointer const_pointer;
typedef typename _Ht::const_reference reference;
typedef typename _Ht::const_reference const_reference;
typedef typename _Ht::const_iterator iterator;
typedef typename _Ht::const_iterator const_iterator;
typedef typename _Ht::allocator_type allocator_type;
hasher hash_funct() const { return _M_ht.hash_funct(); }
key_equal key_eq() const { return _M_ht.key_eq(); }
allocator_type get_allocator() const { return _M_ht.get_allocator(); }
public:
hash_set()
: _M_ht(100, hasher(), key_equal(), allocator_type())
{
}
explicit hash_set(size_type __n)
: _M_ht(__n, hasher(), key_equal(), allocator_type())
{
}
hash_set(size_type __n, const hasher& __hf)
: _M_ht(__n, __hf, key_equal(), allocator_type())
{
}
hash_set(size_type __n, const hasher& __hf, const key_equal& __eql,
const allocator_type& __a = allocator_type())
: _M_ht(__n, __hf, __eql, __a)
{
}
template <class _InputIterator>
hash_set(_InputIterator __f, _InputIterator __l)
: _M_ht(100, hasher(), key_equal(), allocator_type())
{
_M_ht.insert_unique(__f, __l);
}
template <class _InputIterator>
hash_set(_InputIterator __f, _InputIterator __l, size_type __n)
: _M_ht(__n, hasher(), key_equal(), allocator_type())
{
_M_ht.insert_unique(__f, __l);
}
template <class _InputIterator>
hash_set(_InputIterator __f, _InputIterator __l, size_type __n,
const hasher& __hf)
: _M_ht(__n, __hf, key_equal(), allocator_type())
{
_M_ht.insert_unique(__f, __l);
}
template <class _InputIterator>
hash_set(_InputIterator __f, _InputIterator __l, size_type __n,
const hasher& __hf, const key_equal& __eql,
const allocator_type& __a = allocator_type())
: _M_ht(__n, __hf, __eql, __a)
{
_M_ht.insert_unique(__f, __l);
}
public:
size_type size() const { return _M_ht.size(); }
size_type max_size() const { return _M_ht.max_size(); }
bool empty() const { return _M_ht.empty(); }
void swap(hash_set& __hs) { _M_ht.swap(__hs._M_ht); }
friend bool operator==<>(const hash_set&, const hash_set&);
iterator begin() const { return _M_ht.begin(); }
iterator end() const { return _M_ht.end(); }
public:
std::pair<iterator, bool> insert(const value_type& __obj)
{
typedef typename _Ht::iterator _Ht_iterator;
std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique(__obj);
return std::pair<iterator, bool>(__p.first, __p.second);
}
template <class _InputIterator>
void insert(_InputIterator __f, _InputIterator __l)
{
_M_ht.insert_unique(__f, __l);
}
std::pair<iterator, bool> insert_noresize(const value_type& __obj)
{
typedef typename _Ht::iterator _Ht_iterator;
std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique_noresize(__obj);
return std::pair<iterator, bool>(__p.first, __p.second);
}
iterator find(const key_type& __key) const { return _M_ht.find(__key); }
size_type count(const key_type& __key) const { return _M_ht.count(__key); }
std::pair<iterator, iterator> equal_range(const key_type& __key) const
{
return _M_ht.equal_range(__key);
}
size_type erase(const key_type& __key) { return _M_ht.erase(__key); }
void erase(iterator __it) { _M_ht.erase(__it); }
void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
void clear() { _M_ht.clear(); }
public:
void resize(size_type __hint) { _M_ht.resize(__hint); }
size_type bucket_count() const { return _M_ht.bucket_count(); }
size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
size_type elems_in_bucket(size_type __n) const
{
return _M_ht.elems_in_bucket(__n);
}
};
template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1,
const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2)
{
return __hs1._M_ht == __hs2._M_ht;
}
template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
inline bool operator!=(
const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1,
const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2)
{
return !(__hs1 == __hs2);
}
template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
inline void swap(hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2)
{
__hs1.swap(__hs2);
}
template <class _Value, class _HashFcn = hash<_Value>,
class _EqualKey = std::equal_to<_Value>,
class _Alloc = std::allocator<char> >
class hash_multiset;
template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2);
template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>
class hash_multiset
{
private:
typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey,
_Alloc>
_Ht;
_Ht _M_ht;
public:
typedef typename _Ht::key_type key_type;
typedef typename _Ht::value_type value_type;
typedef typename _Ht::hasher hasher;
typedef typename _Ht::key_equal key_equal;
typedef typename _Ht::size_type size_type;
typedef typename _Ht::difference_type difference_type;
typedef typename _Ht::const_pointer pointer;
typedef typename _Ht::const_pointer const_pointer;
typedef typename _Ht::const_reference reference;
typedef typename _Ht::const_reference const_reference;
typedef typename _Ht::const_iterator iterator;
typedef typename _Ht::const_iterator const_iterator;
typedef typename _Ht::allocator_type allocator_type;
hasher hash_funct() const { return _M_ht.hash_funct(); }
key_equal key_eq() const { return _M_ht.key_eq(); }
allocator_type get_allocator() const { return _M_ht.get_allocator(); }
public:
hash_multiset()
: _M_ht(100, hasher(), key_equal(), allocator_type())
{
}
explicit hash_multiset(size_type __n)
: _M_ht(__n, hasher(), key_equal(), allocator_type())
{
}
hash_multiset(size_type __n, const hasher& __hf)
: _M_ht(__n, __hf, key_equal(), allocator_type())
{
}
hash_multiset(size_type __n, const hasher& __hf, const key_equal& __eql,
const allocator_type& __a = allocator_type())
: _M_ht(__n, __hf, __eql, __a)
{
}
template <class _InputIterator>
hash_multiset(_InputIterator __f, _InputIterator __l)
: _M_ht(100, hasher(), key_equal(), allocator_type())
{
_M_ht.insert_equal(__f, __l);
}
template <class _InputIterator>
hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n)
: _M_ht(__n, hasher(), key_equal(), allocator_type())
{
_M_ht.insert_equal(__f, __l);
}
template <class _InputIterator>
hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n,
const hasher& __hf)
: _M_ht(__n, __hf, key_equal(), allocator_type())
{
_M_ht.insert_equal(__f, __l);
}
template <class _InputIterator>
hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n,
const hasher& __hf, const key_equal& __eql,
const allocator_type& __a = allocator_type())
: _M_ht(__n, __hf, __eql, __a)
{
_M_ht.insert_equal(__f, __l);
}
public:
size_type size() const { return _M_ht.size(); }
size_type max_size() const { return _M_ht.max_size(); }
bool empty() const { return _M_ht.empty(); }
void swap(hash_multiset& hs) { _M_ht.swap(hs._M_ht); }
friend bool operator==<>(const hash_multiset&, const hash_multiset&);
iterator begin() const { return _M_ht.begin(); }
iterator end() const { return _M_ht.end(); }
public:
iterator insert(const value_type& __obj)
{
return _M_ht.insert_equal(__obj);
}
template <class _InputIterator>
void insert(_InputIterator __f, _InputIterator __l)
{
_M_ht.insert_equal(__f, __l);
}
iterator insert_noresize(const value_type& __obj)
{
return _M_ht.insert_equal_noresize(__obj);
}
iterator find(const key_type& __key) const { return _M_ht.find(__key); }
size_type count(const key_type& __key) const { return _M_ht.count(__key); }
std::pair<iterator, iterator> equal_range(const key_type& __key) const
{
return _M_ht.equal_range(__key);
}
size_type erase(const key_type& __key) { return _M_ht.erase(__key); }
void erase(iterator __it) { _M_ht.erase(__it); }
void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }
void clear() { _M_ht.clear(); }
public:
void resize(size_type __hint) { _M_ht.resize(__hint); }
size_type bucket_count() const { return _M_ht.bucket_count(); }
size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }
size_type elems_in_bucket(size_type __n) const
{
return _M_ht.elems_in_bucket(__n);
}
};
template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2)
{
return __hs1._M_ht == __hs2._M_ht;
}
template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
inline bool operator!=(
const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2)
{
return !(__hs1 == __hs2);
}
template <class _Val, class _HashFcn, class _EqualKey, class _Alloc>
inline void swap(hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1,
hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2)
{
__hs1.swap(__hs2);
}
} // namespace @KWSYS_NAMESPACE@
#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
# pragma reset woff 1174
# pragma reset woff 1375
#endif
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif
-995
View File
@@ -1,995 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
/*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
#ifdef __BORLANDC__
# pragma warn - 8027 /* 'for' not inlined. */
# pragma warn - 8026 /* 'exception' not inlined. */
#endif
#ifndef @KWSYS_NAMESPACE@_hashtable_hxx
# define @KWSYS_NAMESPACE@_hashtable_hxx
# include <@KWSYS_NAMESPACE@/Configure.hxx>
# include <algorithm> // lower_bound
# include <iterator> // iterator_traits
# include <memory> // allocator
# include <stddef.h> // size_t
# include <utility> // pair
# include <vector> // vector
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4284)
# pragma warning(disable : 4786)
# pragma warning(disable : 4512) /* no assignment operator for class */
# endif
# if defined(__sgi) && !defined(__GNUC__)
# pragma set woff 3970 /* pointer to int conversion */ 3321 3968
# endif
// In C++11, clang will warn about using dynamic exception specifications
// as they are deprecated. But as this class is trying to faithfully
// mimic unordered_set and unordered_map, we want to keep the 'throw()'
// decorations below. So we suppress the warning.
# if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wdeprecated")
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated"
# endif
# endif
namespace @KWSYS_NAMESPACE@ {
template <class _Val>
struct _Hashtable_node
{
_Hashtable_node* _M_next;
_Val _M_val;
void public_method_to_quiet_warning_about_all_methods_private();
private:
void operator=(_Hashtable_node<_Val> const&) = delete;
};
template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
class _EqualKey, class _Alloc = std::allocator<char> >
class hashtable;
template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
class _EqualKey, class _Alloc>
struct _Hashtable_iterator;
template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
class _EqualKey, class _Alloc>
struct _Hashtable_const_iterator;
template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
class _EqualKey, class _Alloc>
struct _Hashtable_iterator
{
typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>
_Hashtable;
typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey,
_Alloc>
iterator;
typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
_EqualKey, _Alloc>
const_iterator;
typedef _Hashtable_node<_Val> _Node;
typedef std::forward_iterator_tag iterator_category;
typedef _Val value_type;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef _Val& reference;
typedef _Val* pointer;
_Node* _M_cur;
_Hashtable* _M_ht;
_Hashtable_iterator(_Node* __n, _Hashtable* __tab)
: _M_cur(__n)
, _M_ht(__tab)
{
}
_Hashtable_iterator() {}
reference operator*() const { return _M_cur->_M_val; }
pointer operator->() const { return &(operator*()); }
iterator& operator++();
iterator operator++(int);
bool operator==(const iterator& __it) const { return _M_cur == __it._M_cur; }
bool operator!=(const iterator& __it) const { return _M_cur != __it._M_cur; }
};
template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
class _EqualKey, class _Alloc>
struct _Hashtable_const_iterator
{
typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>
_Hashtable;
typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey,
_Alloc>
iterator;
typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
_EqualKey, _Alloc>
const_iterator;
typedef _Hashtable_node<_Val> _Node;
typedef std::forward_iterator_tag iterator_category;
typedef _Val value_type;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef const _Val& reference;
typedef const _Val* pointer;
const _Node* _M_cur;
const _Hashtable* _M_ht;
_Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab)
: _M_cur(__n)
, _M_ht(__tab)
{
}
_Hashtable_const_iterator() {}
_Hashtable_const_iterator(const iterator& __it)
: _M_cur(__it._M_cur)
, _M_ht(__it._M_ht)
{
}
reference operator*() const { return _M_cur->_M_val; }
pointer operator->() const { return &(operator*()); }
const_iterator& operator++();
const_iterator operator++(int);
bool operator==(const const_iterator& __it) const
{
return _M_cur == __it._M_cur;
}
bool operator!=(const const_iterator& __it) const
{
return _M_cur != __it._M_cur;
}
};
// Note: assumes long is at least 32 bits.
enum
{
_stl_num_primes = 31
};
// create a function with a static local to that function that returns
// the static
static inline const unsigned long* get_stl_prime_list()
{
static const unsigned long _stl_prime_list[_stl_num_primes] = {
5ul, 11ul, 23ul, 53ul, 97ul,
193ul, 389ul, 769ul, 1543ul, 3079ul,
6151ul, 12289ul, 24593ul, 49157ul, 98317ul,
196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul,
6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul,
201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul,
4294967291ul
};
return &_stl_prime_list[0];
}
static inline size_t _stl_next_prime(size_t __n)
{
const unsigned long* __first = get_stl_prime_list();
const unsigned long* __last = get_stl_prime_list() + (int)_stl_num_primes;
const unsigned long* pos = std::lower_bound(__first, __last, __n);
return pos == __last ? *(__last - 1) : *pos;
}
// Forward declaration of operator==.
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
class hashtable;
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2);
// Hashtables handle allocators a bit differently than other containers
// do. If we're using standard-conforming allocators, then a hashtable
// unconditionally has a member variable to hold its allocator, even if
// it so happens that all instances of the allocator type are identical.
// This is because, for hashtables, this extra storage is negligible.
// Additionally, a base class wouldn't serve any other purposes; it
// wouldn't, for example, simplify the exception-handling code.
template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
class _EqualKey, class _Alloc>
class hashtable
{
public:
typedef _Key key_type;
typedef _Val value_type;
typedef _HashFcn hasher;
typedef _EqualKey key_equal;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
hasher hash_funct() const { return _M_hash; }
key_equal key_eq() const { return _M_equals; }
private:
typedef _Hashtable_node<_Val> _Node;
public:
typedef typename _Alloc::template rebind<_Val>::other allocator_type;
allocator_type get_allocator() const { return _M_node_allocator; }
private:
typedef
typename _Alloc::template rebind<_Node>::other _M_node_allocator_type;
typedef
typename _Alloc::template rebind<_Node*>::other _M_node_ptr_allocator_type;
typedef std::vector<_Node*, _M_node_ptr_allocator_type> _M_buckets_type;
private:
_M_node_allocator_type _M_node_allocator;
hasher _M_hash;
key_equal _M_equals;
_ExtractKey _M_get_key;
_M_buckets_type _M_buckets;
size_type _M_num_elements;
_Node* _M_get_node() { return _M_node_allocator.allocate(1); }
void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); }
public:
typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey,
_Alloc>
iterator;
typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
_EqualKey, _Alloc>
const_iterator;
friend struct _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey,
_EqualKey, _Alloc>;
friend struct _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
_EqualKey, _Alloc>;
public:
hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql,
const _ExtractKey& __ext,
const allocator_type& __a = allocator_type())
: _M_node_allocator(__a)
, _M_hash(__hf)
, _M_equals(__eql)
, _M_get_key(__ext)
, _M_buckets(__a)
, _M_num_elements(0)
{
_M_initialize_buckets(__n);
}
hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql,
const allocator_type& __a = allocator_type())
: _M_node_allocator(__a)
, _M_hash(__hf)
, _M_equals(__eql)
, _M_get_key(_ExtractKey())
, _M_buckets(__a)
, _M_num_elements(0)
{
_M_initialize_buckets(__n);
}
hashtable(const hashtable& __ht)
: _M_node_allocator(__ht.get_allocator())
, _M_hash(__ht._M_hash)
, _M_equals(__ht._M_equals)
, _M_get_key(__ht._M_get_key)
, _M_buckets(__ht.get_allocator())
, _M_num_elements(0)
{
_M_copy_from(__ht);
}
hashtable& operator=(const hashtable& __ht)
{
if (&__ht != this) {
clear();
_M_hash = __ht._M_hash;
_M_equals = __ht._M_equals;
_M_get_key = __ht._M_get_key;
_M_copy_from(__ht);
}
return *this;
}
~hashtable() { clear(); }
size_type size() const { return _M_num_elements; }
size_type max_size() const { return size_type(-1); }
bool empty() const { return size() == 0; }
void swap(hashtable& __ht)
{
std::swap(_M_hash, __ht._M_hash);
std::swap(_M_equals, __ht._M_equals);
std::swap(_M_get_key, __ht._M_get_key);
_M_buckets.swap(__ht._M_buckets);
std::swap(_M_num_elements, __ht._M_num_elements);
}
iterator begin()
{
for (size_type __n = 0; __n < _M_buckets.size(); ++__n)
if (_M_buckets[__n])
return iterator(_M_buckets[__n], this);
return end();
}
iterator end() { return iterator(nullptr, 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(nullptr, this); }
friend bool operator==<>(const hashtable&, const hashtable&);
public:
size_type bucket_count() const { return _M_buckets.size(); }
size_type max_bucket_count() const
{
return get_stl_prime_list()[(int)_stl_num_primes - 1];
}
size_type elems_in_bucket(size_type __bucket) const
{
size_type __result = 0;
for (_Node* __cur = _M_buckets[__bucket]; __cur; __cur = __cur->_M_next)
__result += 1;
return __result;
}
std::pair<iterator, bool> insert_unique(const value_type& __obj)
{
resize(_M_num_elements + 1);
return insert_unique_noresize(__obj);
}
iterator insert_equal(const value_type& __obj)
{
resize(_M_num_elements + 1);
return insert_equal_noresize(__obj);
}
std::pair<iterator, bool> insert_unique_noresize(const value_type& __obj);
iterator insert_equal_noresize(const value_type& __obj);
template <class _InputIterator>
void insert_unique(_InputIterator __f, _InputIterator __l)
{
insert_unique(
__f, __l,
typename std::iterator_traits<_InputIterator>::iterator_category());
}
template <class _InputIterator>
void insert_equal(_InputIterator __f, _InputIterator __l)
{
insert_equal(
__f, __l,
typename std::iterator_traits<_InputIterator>::iterator_category());
}
template <class _InputIterator>
void insert_unique(_InputIterator __f, _InputIterator __l,
std::input_iterator_tag)
{
for (; __f != __l; ++__f)
insert_unique(*__f);
}
template <class _InputIterator>
void insert_equal(_InputIterator __f, _InputIterator __l,
std::input_iterator_tag)
{
for (; __f != __l; ++__f)
insert_equal(*__f);
}
template <class _ForwardIterator>
void insert_unique(_ForwardIterator __f, _ForwardIterator __l,
std::forward_iterator_tag)
{
size_type __n = 0;
std::distance(__f, __l, __n);
resize(_M_num_elements + __n);
for (; __n > 0; --__n, ++__f)
insert_unique_noresize(*__f);
}
template <class _ForwardIterator>
void insert_equal(_ForwardIterator __f, _ForwardIterator __l,
std::forward_iterator_tag)
{
size_type __n = 0;
std::distance(__f, __l, __n);
resize(_M_num_elements + __n);
for (; __n > 0; --__n, ++__f)
insert_equal_noresize(*__f);
}
reference find_or_insert(const value_type& __obj);
iterator find(const key_type& __key)
{
size_type __n = _M_bkt_num_key(__key);
_Node* __first;
for (__first = _M_buckets[__n];
__first && !_M_equals(_M_get_key(__first->_M_val), __key);
__first = __first->_M_next) {
}
return iterator(__first, this);
}
const_iterator find(const key_type& __key) const
{
size_type __n = _M_bkt_num_key(__key);
const _Node* __first;
for (__first = _M_buckets[__n];
__first && !_M_equals(_M_get_key(__first->_M_val), __key);
__first = __first->_M_next) {
}
return const_iterator(__first, this);
}
size_type count(const key_type& __key) const
{
const size_type __n = _M_bkt_num_key(__key);
size_type __result = 0;
for (const _Node* __cur = _M_buckets[__n]; __cur; __cur = __cur->_M_next)
if (_M_equals(_M_get_key(__cur->_M_val), __key))
++__result;
return __result;
}
std::pair<iterator, iterator> equal_range(const key_type& __key);
std::pair<const_iterator, const_iterator> equal_range(
const key_type& __key) const;
size_type erase(const key_type& __key);
void erase(const iterator& __it);
void erase(iterator __first, iterator __last);
void erase(const const_iterator& __it);
void erase(const_iterator __first, const_iterator __last);
void resize(size_type __num_elements_hint);
void clear();
private:
size_type _M_next_size(size_type __n) const { return _stl_next_prime(__n); }
void _M_initialize_buckets(size_type __n)
{
const size_type __n_buckets = _M_next_size(__n);
_M_buckets.reserve(__n_buckets);
_M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*)nullptr);
_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 = nullptr;
try {
construct(&__n->_M_val, __obj);
return __n;
} catch (...) {
_M_put_node(__n);
throw;
}
}
void _M_delete_node(_Node* __n)
{
destroy(&__n->_M_val);
_M_put_node(__n);
}
void _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last);
void _M_erase_bucket(const size_type __n, _Node* __last);
void _M_copy_from(const hashtable& __ht);
};
template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>&
_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++()
{
const _Node* __old = _M_cur;
_M_cur = _M_cur->_M_next;
if (!_M_cur) {
size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
_M_cur = _M_ht->_M_buckets[__bucket];
}
return *this;
}
template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
inline _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>
_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int)
{
iterator __tmp = *this;
++*this;
return __tmp;
}
template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>&
_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++()
{
const _Node* __old = _M_cur;
_M_cur = _M_cur->_M_next;
if (!_M_cur) {
size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
_M_cur = _M_ht->_M_buckets[__bucket];
}
return *this;
}
template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
inline _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>
_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int)
{
const_iterator __tmp = *this;
++*this;
return __tmp;
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2)
{
typedef typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_Node _Node;
if (__ht1._M_buckets.size() != __ht2._M_buckets.size())
return false;
for (int __n = 0; __n < __ht1._M_buckets.size(); ++__n) {
_Node* __cur1 = __ht1._M_buckets[__n];
_Node* __cur2 = __ht2._M_buckets[__n];
for (; __cur1 && __cur2 && __cur1->_M_val == __cur2->_M_val;
__cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next) {
}
if (__cur1 || __cur2)
return false;
}
return true;
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
inline bool operator!=(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2)
{
return !(__ht1 == __ht2);
}
template <class _Val, class _Key, class _HF, class _Extract, class _EqKey,
class _All>
inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1,
hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2)
{
__ht1.swap(__ht2);
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator, bool>
hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_unique_noresize(
const value_type& __obj)
{
const size_type __n = _M_bkt_num(__obj);
_Node* __first = _M_buckets[__n];
for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
return std::pair<iterator, bool>(iterator(__cur, this), false);
_Node* __tmp = _M_new_node(__obj);
__tmp->_M_next = __first;
_M_buckets[__n] = __tmp;
++_M_num_elements;
return std::pair<iterator, bool>(iterator(__tmp, this), true);
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator
hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_equal_noresize(
const value_type& __obj)
{
const size_type __n = _M_bkt_num(__obj);
_Node* __first = _M_buckets[__n];
for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) {
_Node* __tmp = _M_new_node(__obj);
__tmp->_M_next = __cur->_M_next;
__cur->_M_next = __tmp;
++_M_num_elements;
return iterator(__tmp, this);
}
_Node* __tmp = _M_new_node(__obj);
__tmp->_M_next = __first;
_M_buckets[__n] = __tmp;
++_M_num_elements;
return iterator(__tmp, this);
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::reference
hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::find_or_insert(
const value_type& __obj)
{
resize(_M_num_elements + 1);
size_type __n = _M_bkt_num(__obj);
_Node* __first = _M_buckets[__n];
for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
return __cur->_M_val;
_Node* __tmp = _M_new_node(__obj);
__tmp->_M_next = __first;
_M_buckets[__n] = __tmp;
++_M_num_elements;
return __tmp->_M_val;
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator,
typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator>
hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range(const key_type& __key)
{
typedef std::pair<iterator, iterator> _Pii;
const size_type __n = _M_bkt_num_key(__key);
for (_Node* __first = _M_buckets[__n]; __first; __first = __first->_M_next)
if (_M_equals(_M_get_key(__first->_M_val), __key)) {
for (_Node* __cur = __first->_M_next; __cur; __cur = __cur->_M_next)
if (!_M_equals(_M_get_key(__cur->_M_val), __key))
return _Pii(iterator(__first, this), iterator(__cur, this));
for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
if (_M_buckets[__m])
return _Pii(iterator(__first, this),
iterator(_M_buckets[__m], this));
return _Pii(iterator(__first, this), end());
}
return _Pii(end(), end());
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator,
typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator>
hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range(
const key_type& __key) const
{
typedef std::pair<const_iterator, const_iterator> _Pii;
const size_type __n = _M_bkt_num_key(__key);
for (const _Node* __first = _M_buckets[__n]; __first;
__first = __first->_M_next) {
if (_M_equals(_M_get_key(__first->_M_val), __key)) {
for (const _Node* __cur = __first->_M_next; __cur;
__cur = __cur->_M_next)
if (!_M_equals(_M_get_key(__cur->_M_val), __key))
return _Pii(const_iterator(__first, this),
const_iterator(__cur, this));
for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
if (_M_buckets[__m])
return _Pii(const_iterator(__first, this),
const_iterator(_M_buckets[__m], this));
return _Pii(const_iterator(__first, this), end());
}
}
return _Pii(end(), end());
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::size_type
hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const key_type& __key)
{
const size_type __n = _M_bkt_num_key(__key);
_Node* __first = _M_buckets[__n];
size_type __erased = 0;
if (__first) {
_Node* __cur = __first;
_Node* __next = __cur->_M_next;
while (__next) {
if (_M_equals(_M_get_key(__next->_M_val), __key)) {
__cur->_M_next = __next->_M_next;
_M_delete_node(__next);
__next = __cur->_M_next;
++__erased;
--_M_num_elements;
} else {
__cur = __next;
__next = __cur->_M_next;
}
}
if (_M_equals(_M_get_key(__first->_M_val), __key)) {
_M_buckets[__n] = __first->_M_next;
_M_delete_node(__first);
++__erased;
--_M_num_elements;
}
}
return __erased;
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const iterator& __it)
{
_Node* __p = __it._M_cur;
if (__p) {
const size_type __n = _M_bkt_num(__p->_M_val);
_Node* __cur = _M_buckets[__n];
if (__cur == __p) {
_M_buckets[__n] = __cur->_M_next;
_M_delete_node(__cur);
--_M_num_elements;
} else {
_Node* __next = __cur->_M_next;
while (__next) {
if (__next == __p) {
__cur->_M_next = __next->_M_next;
_M_delete_node(__next);
--_M_num_elements;
break;
} else {
__cur = __next;
__next = __cur->_M_next;
}
}
}
}
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(iterator __first,
iterator __last)
{
size_type __f_bucket =
__first._M_cur ? _M_bkt_num(__first._M_cur->_M_val) : _M_buckets.size();
size_type __l_bucket =
__last._M_cur ? _M_bkt_num(__last._M_cur->_M_val) : _M_buckets.size();
if (__first._M_cur == __last._M_cur)
return;
else if (__f_bucket == __l_bucket)
_M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur);
else {
_M_erase_bucket(__f_bucket, __first._M_cur, nullptr);
for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n)
_M_erase_bucket(__n, nullptr);
if (__l_bucket != _M_buckets.size())
_M_erase_bucket(__l_bucket, __last._M_cur);
}
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(
const_iterator __first, const_iterator __last)
{
erase(iterator(const_cast<_Node*>(__first._M_cur),
const_cast<hashtable*>(__first._M_ht)),
iterator(const_cast<_Node*>(__last._M_cur),
const_cast<hashtable*>(__last._M_ht)));
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(
const const_iterator& __it)
{
erase(iterator(const_cast<_Node*>(__it._M_cur),
const_cast<hashtable*>(__it._M_ht)));
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::resize(
size_type __num_elements_hint)
{
const size_type __old_n = _M_buckets.size();
if (__num_elements_hint > __old_n) {
const size_type __n = _M_next_size(__num_elements_hint);
if (__n > __old_n) {
_M_buckets_type __tmp(__n, (_Node*)(nullptr),
_M_buckets.get_allocator());
try {
for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) {
_Node* __first = _M_buckets[__bucket];
while (__first) {
size_type __new_bucket = _M_bkt_num(__first->_M_val, __n);
_M_buckets[__bucket] = __first->_M_next;
__first->_M_next = __tmp[__new_bucket];
__tmp[__new_bucket] = __first;
__first = _M_buckets[__bucket];
}
}
_M_buckets.swap(__tmp);
} catch (...) {
for (size_type __bucket = 0; __bucket < __tmp.size(); ++__bucket) {
while (__tmp[__bucket]) {
_Node* __next = __tmp[__bucket]->_M_next;
_M_delete_node(__tmp[__bucket]);
__tmp[__bucket] = __next;
}
}
throw;
}
}
}
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket(
const size_type __n, _Node* __first, _Node* __last)
{
_Node* __cur = _M_buckets[__n];
if (__cur == __first)
_M_erase_bucket(__n, __last);
else {
_Node* __next;
for (__next = __cur->_M_next; __next != __first;
__cur = __next, __next = __cur->_M_next)
;
while (__next != __last) {
__cur->_M_next = __next->_M_next;
_M_delete_node(__next);
__next = __cur->_M_next;
--_M_num_elements;
}
}
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket(
const size_type __n, _Node* __last)
{
_Node* __cur = _M_buckets[__n];
while (__cur != __last) {
_Node* __next = __cur->_M_next;
_M_delete_node(__cur);
__cur = __next;
_M_buckets[__n] = __cur;
--_M_num_elements;
}
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::clear()
{
for (size_type __i = 0; __i < _M_buckets.size(); ++__i) {
_Node* __cur = _M_buckets[__i];
while (__cur != nullptr) {
_Node* __next = __cur->_M_next;
_M_delete_node(__cur);
__cur = __next;
}
_M_buckets[__i] = nullptr;
}
_M_num_elements = 0;
}
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_copy_from(
const hashtable& __ht)
{
_M_buckets.clear();
_M_buckets.reserve(__ht._M_buckets.size());
_M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*)nullptr);
try {
for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) {
const _Node* __cur = __ht._M_buckets[__i];
if (__cur) {
_Node* __copy = _M_new_node(__cur->_M_val);
_M_buckets[__i] = __copy;
for (_Node* __next = __cur->_M_next; __next;
__cur = __next, __next = __cur->_M_next) {
__copy->_M_next = _M_new_node(__next->_M_val);
__copy = __copy->_M_next;
}
}
}
_M_num_elements = __ht._M_num_elements;
} catch (...) {
clear();
throw;
}
}
} // namespace @KWSYS_NAMESPACE@
// Undo warning suppression.
# if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wdeprecated")
# pragma clang diagnostic pop
# endif
# endif
# if defined(_MSC_VER)
# pragma warning(pop)
# endif
#endif
-41
View File
@@ -1,41 +0,0 @@
#!/usr/bin/perl
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
if ( $#ARGV+1 < 2 )
{
print "Usage: ./kwsysHeaderDump.pl <name> <header>\n";
exit(1);
}
$name = $ARGV[0];
$max = 0;
open(INFILE, $ARGV[1]);
while (chomp ($line = <INFILE>))
{
if (($line !~ /^\#/) &&
($line =~ s/.*kwsys${name}_([A-Za-z0-9_]*).*/\1/) &&
($i{$line}++ < 1))
{
push(@lines, "$line");
if (length($line) > $max)
{
$max = length($line);
}
}
}
close(INFILE);
$width = $max + 13;
print sprintf("#define %-${width}s kwsys_ns(${name})\n", "kwsys${name}");
foreach $l (@lines)
{
print sprintf("#define %-${width}s kwsys_ns(${name}_$l)\n",
"kwsys${name}_$l");
}
print "\n";
print sprintf("# undef kwsys${name}\n");
foreach $l (@lines)
{
print sprintf("# undef kwsys${name}_$l\n");
}
@@ -1,216 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing#kwsys for details.
SET(KWSYS_PLATFORM_TEST_FILE_C kwsysPlatformTestsC.c)
SET(KWSYS_PLATFORM_TEST_FILE_CXX kwsysPlatformTestsCXX.cxx)
MACRO(KWSYS_PLATFORM_TEST lang var description invert)
IF(NOT DEFINED ${var}_COMPILED)
MESSAGE(STATUS "${description}")
set(maybe_cxx_standard "")
if(CMAKE_VERSION VERSION_LESS 3.8 AND CMAKE_CXX_STANDARD)
set(maybe_cxx_standard "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}")
endif()
TRY_COMPILE(${var}_COMPILED
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS}
CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}"
${maybe_cxx_standard}
OUTPUT_VARIABLE OUTPUT)
IF(${var}_COMPILED)
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"${description} compiled with the following output:\n${OUTPUT}\n\n")
ELSE()
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"${description} failed to compile with the following output:\n${OUTPUT}\n\n")
ENDIF()
IF(${invert} MATCHES INVERT)
IF(${var}_COMPILED)
MESSAGE(STATUS "${description} - no")
ELSE()
MESSAGE(STATUS "${description} - yes")
ENDIF()
ELSE()
IF(${var}_COMPILED)
MESSAGE(STATUS "${description} - yes")
ELSE()
MESSAGE(STATUS "${description} - no")
ENDIF()
ENDIF()
ENDIF()
IF(${invert} MATCHES INVERT)
IF(${var}_COMPILED)
SET(${var} 0)
ELSE()
SET(${var} 1)
ENDIF()
ELSE()
IF(${var}_COMPILED)
SET(${var} 1)
ELSE()
SET(${var} 0)
ENDIF()
ENDIF()
ENDMACRO()
MACRO(KWSYS_PLATFORM_TEST_RUN lang var description invert)
IF(NOT DEFINED ${var})
MESSAGE(STATUS "${description}")
TRY_RUN(${var} ${var}_COMPILED
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS}
OUTPUT_VARIABLE OUTPUT)
# Note that ${var} will be a 0 return value on success.
IF(${var}_COMPILED)
IF(${var})
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n")
ELSE()
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"${description} compiled and ran with the following output:\n${OUTPUT}\n\n")
ENDIF()
ELSE()
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"${description} failed to compile with the following output:\n${OUTPUT}\n\n")
SET(${var} -1 CACHE INTERNAL "${description} failed to compile.")
ENDIF()
IF(${invert} MATCHES INVERT)
IF(${var}_COMPILED)
IF(${var})
MESSAGE(STATUS "${description} - yes")
ELSE()
MESSAGE(STATUS "${description} - no")
ENDIF()
ELSE()
MESSAGE(STATUS "${description} - failed to compile")
ENDIF()
ELSE()
IF(${var}_COMPILED)
IF(${var})
MESSAGE(STATUS "${description} - no")
ELSE()
MESSAGE(STATUS "${description} - yes")
ENDIF()
ELSE()
MESSAGE(STATUS "${description} - failed to compile")
ENDIF()
ENDIF()
ENDIF()
IF(${invert} MATCHES INVERT)
IF(${var}_COMPILED)
IF(${var})
SET(${var} 1)
ELSE()
SET(${var} 0)
ENDIF()
ELSE()
SET(${var} 1)
ENDIF()
ELSE()
IF(${var}_COMPILED)
IF(${var})
SET(${var} 0)
ELSE()
SET(${var} 1)
ENDIF()
ELSE()
SET(${var} 0)
ENDIF()
ENDIF()
ENDMACRO()
MACRO(KWSYS_PLATFORM_C_TEST var description invert)
SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES})
SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS})
KWSYS_PLATFORM_TEST(C "${var}" "${description}" "${invert}")
SET(KWSYS_PLATFORM_TEST_DEFINES)
SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
ENDMACRO()
MACRO(KWSYS_PLATFORM_C_TEST_RUN var description invert)
SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES})
SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS})
KWSYS_PLATFORM_TEST_RUN(C "${var}" "${description}" "${invert}")
SET(KWSYS_PLATFORM_TEST_DEFINES)
SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
ENDMACRO()
MACRO(KWSYS_PLATFORM_CXX_TEST var description invert)
SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES})
SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS})
SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES})
KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}")
SET(KWSYS_PLATFORM_TEST_DEFINES)
SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES)
ENDMACRO()
MACRO(KWSYS_PLATFORM_CXX_TEST_RUN var description invert)
SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES})
SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS})
KWSYS_PLATFORM_TEST_RUN(CXX "${var}" "${description}" "${invert}")
SET(KWSYS_PLATFORM_TEST_DEFINES)
SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS)
ENDMACRO()
#-----------------------------------------------------------------------------
# KWSYS_PLATFORM_INFO_TEST(lang var description)
#
# Compile test named by ${var} and store INFO strings extracted from binary.
MACRO(KWSYS_PLATFORM_INFO_TEST lang var description)
# We can implement this macro on CMake 2.6 and above.
IF("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6)
SET(${var} "")
ELSE()
# Choose a location for the result binary.
SET(KWSYS_PLATFORM_INFO_FILE
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${var}.bin)
# Compile the test binary.
IF(NOT EXISTS ${KWSYS_PLATFORM_INFO_FILE})
MESSAGE(STATUS "${description}")
TRY_COMPILE(${var}_COMPILED
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}}
COMPILE_DEFINITIONS -DTEST_${var}
${KWSYS_PLATFORM_${lang}_TEST_DEFINES}
${KWSYS_PLATFORM_${lang}_TEST_EXTRA_FLAGS}
OUTPUT_VARIABLE OUTPUT
COPY_FILE ${KWSYS_PLATFORM_INFO_FILE}
)
IF(${var}_COMPILED)
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"${description} compiled with the following output:\n${OUTPUT}\n\n")
ELSE()
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"${description} failed to compile with the following output:\n${OUTPUT}\n\n")
ENDIF()
IF(${var}_COMPILED)
MESSAGE(STATUS "${description} - compiled")
ELSE()
MESSAGE(STATUS "${description} - failed")
ENDIF()
ENDIF()
# Parse info strings out of the compiled binary.
IF(${var}_COMPILED)
FILE(STRINGS ${KWSYS_PLATFORM_INFO_FILE} ${var} REGEX "INFO:[A-Za-z0-9]+\\[[^]]*\\]")
ELSE()
SET(${var} "")
ENDIF()
SET(KWSYS_PLATFORM_INFO_FILE)
ENDIF()
ENDMACRO()
-108
View File
@@ -1,108 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
/*
Macros to define main() in a cross-platform way.
Usage:
int KWSYS_PLATFORM_TEST_C_MAIN()
{
return 0;
}
int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv)
{
(void)argc; (void)argv;
return 0;
}
*/
#if defined(__CLASSIC_C__)
# define KWSYS_PLATFORM_TEST_C_MAIN() main()
# define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) \
main(argc, argv) int argc; \
char* argv[];
#else
# define KWSYS_PLATFORM_TEST_C_MAIN() main(void)
# define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) \
main(int argc, char* argv[])
#endif
#ifdef TEST_KWSYS_C_HAS_PTRDIFF_T
# include <stddef.h>
int f(ptrdiff_t n)
{
return n > 0;
}
int KWSYS_PLATFORM_TEST_C_MAIN()
{
char* p = 0;
ptrdiff_t d = p - p;
(void)d;
return f(p - p);
}
#endif
#ifdef TEST_KWSYS_C_HAS_SSIZE_T
# include <unistd.h>
int f(ssize_t n)
{
return (int)n;
}
int KWSYS_PLATFORM_TEST_C_MAIN()
{
ssize_t n = 0;
return f(n);
}
#endif
#ifdef TEST_KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC
# if defined(__APPLE__)
# include <AvailabilityMacros.h>
# if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
# error "clock_gettime not available on macOS < 10.12"
# endif
# endif
# include <time.h>
int KWSYS_PLATFORM_TEST_C_MAIN()
{
struct timespec ts;
return clock_gettime(CLOCK_MONOTONIC, &ts);
}
#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
@@ -1,335 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifdef TEST_KWSYS_CXX_HAS_CSTDIO
# include <cstdio>
int main()
{
return 0;
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_LONG_LONG
long long f(long long n)
{
return n;
}
int main()
{
long long n = 0;
return static_cast<int>(f(n));
}
#endif
#ifdef TEST_KWSYS_CXX_HAS___INT64
__int64 f(__int64 n)
{
return n;
}
int main()
{
__int64 n = 0;
return static_cast<int>(f(n));
}
#endif
#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIM
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
int main()
{
struct stat stat1;
(void)stat1.st_mtim.tv_sec;
(void)stat1.st_mtim.tv_nsec;
return 0;
}
#endif
#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIMESPEC
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
int main()
{
struct stat stat1;
(void)stat1.st_mtimespec.tv_sec;
(void)stat1.st_mtimespec.tv_nsec;
return 0;
}
#endif
#ifdef TEST_KWSYS_CXX_SAME_LONG_AND___INT64
void function(long**)
{
}
int main()
{
__int64** p = 0;
function(p);
return 0;
}
#endif
#ifdef TEST_KWSYS_CXX_SAME_LONG_LONG_AND___INT64
void function(long long**)
{
}
int main()
{
__int64** p = 0;
function(p);
return 0;
}
#endif
#ifdef TEST_KWSYS_IOS_HAS_ISTREAM_LONG_LONG
# include <iostream>
int test_istream(std::istream& is, long long& x)
{
return (is >> x) ? 1 : 0;
}
int main()
{
long long x = 0;
return test_istream(std::cin, x);
}
#endif
#ifdef TEST_KWSYS_IOS_HAS_OSTREAM_LONG_LONG
# include <iostream>
int test_ostream(std::ostream& os, long long x)
{
return (os << x) ? 1 : 0;
}
int main()
{
long long x = 0;
return test_ostream(std::cout, x);
}
#endif
#ifdef TEST_KWSYS_IOS_HAS_ISTREAM___INT64
# include <iostream>
int test_istream(std::istream& is, __int64& x)
{
return (is >> x) ? 1 : 0;
}
int main()
{
__int64 x = 0;
return test_istream(std::cin, x);
}
#endif
#ifdef TEST_KWSYS_IOS_HAS_OSTREAM___INT64
# include <iostream>
int test_ostream(std::ostream& os, __int64 x)
{
return (os << x) ? 1 : 0;
}
int main()
{
__int64 x = 0;
return test_ostream(std::cout, x);
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_SETENV
# include <stdlib.h>
int main()
{
return setenv("A", "B", 1);
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_UNSETENV
# include <stdlib.h>
int main()
{
unsetenv("A");
return 0;
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
# include <stdlib.h>
int main()
{
char* e = environ[0];
return e ? 0 : 1;
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_GETLOADAVG
// Match feature definitions from SystemInformation.cxx
# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
# endif
# include <stdlib.h>
int main()
{
double loadavg[3] = { 0.0, 0.0, 0.0 };
return getloadavg(loadavg, 3);
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64
# include <sys/resource.h>
int main()
{
struct rlimit64 rlim;
return getrlimit64(0, &rlim);
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_ATOLL
# include <stdlib.h>
int main()
{
const char* str = "1024";
return static_cast<int>(atoll(str));
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_ATOL
# include <stdlib.h>
int main()
{
const char* str = "1024";
return static_cast<int>(atol(str));
}
#endif
#ifdef TEST_KWSYS_CXX_HAS__ATOI64
# include <stdlib.h>
int main()
{
const char* str = "1024";
return static_cast<int>(_atoi64(str));
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_UTIMES
# include <sys/time.h>
int main()
{
struct timeval* current_time = 0;
return utimes("/example", current_time);
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_UTIMENSAT
# include <fcntl.h>
# include <sys/stat.h>
# if defined(__APPLE__)
# include <AvailabilityMacros.h>
# if MAC_OS_X_VERSION_MIN_REQUIRED < 101300
# error "utimensat not available on macOS < 10.13"
# endif
# endif
int main()
{
struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, UTIME_NOW } };
return utimensat(AT_FDCWD, "/example", times, AT_SYMLINK_NOFOLLOW);
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_BACKTRACE
# if defined(__PATHSCALE__) || defined(__PATHCC__) || \
(defined(__LSB_VERSION__) && (__LSB_VERSION__ < 41))
backtrace does not work with this compiler or os
# endif
# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
# endif
# include <execinfo.h>
int main()
{
void* stackSymbols[256];
backtrace(stackSymbols, 256);
backtrace_symbols(&stackSymbols[0], 1);
return 0;
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_DLADDR
# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
# endif
# include <dlfcn.h>
int main()
{
Dl_info info;
int ierr = dladdr((void*)main, &info);
return 0;
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_CXXABI
# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
# endif
# if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5130 && __linux && \
__SUNPRO_CC_COMPAT == 'G'
# include <iostream>
# endif
# include <cxxabi.h>
int main()
{
int status = 0;
size_t bufferLen = 512;
char buffer[512] = { '\0' };
const char* function = "_ZN5kwsys17SystemInformation15GetProgramStackEii";
char* demangledFunction =
abi::__cxa_demangle(function, buffer, &bufferLen, &status);
return status;
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM
int main()
{
int a = 1;
__asm {
xor EBX, EBX;
mov a, EBX;
}
return a;
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM_CPUID
int main()
{
int a = 0;
__asm {
xor EAX, EAX;
cpuid;
mov a, EAX;
}
return a;
}
#endif
#ifdef TEST_KWSYS_STL_HAS_WSTRING
# include <string>
void f(std::wstring*)
{
}
int main()
{
return 0;
}
#endif
#ifdef TEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H
# include <ext/stdio_filebuf.h>
int main()
{
return 0;
}
#endif
-34
View File
@@ -1,34 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef KWSYS_NAMESPACE
# error "Do not include kwsysPrivate.h outside of kwsys c and cxx files."
#endif
#ifndef _kwsysPrivate_h
# define _kwsysPrivate_h
/*
Define KWSYS_HEADER macro to help the c and cxx files include kwsys
headers from the configured namespace directory. The macro can be
used like this:
#include KWSYS_HEADER(Directory.hxx)
#include KWSYS_HEADER(std/vector)
*/
/* clang-format off */
#define KWSYS_HEADER(x) KWSYS_HEADER0(KWSYS_NAMESPACE/x)
/* clang-format on */
# define KWSYS_HEADER0(x) KWSYS_HEADER1(x)
# define KWSYS_HEADER1(x) <x>
/*
Define KWSYS_NAMESPACE_STRING to be a string constant containing the
name configured for this instance of the kwsys library.
*/
# define KWSYS_NAMESPACE_STRING KWSYS_NAMESPACE_STRING0(KWSYS_NAMESPACE)
# define KWSYS_NAMESPACE_STRING0(x) KWSYS_NAMESPACE_STRING1(x)
# define KWSYS_NAMESPACE_STRING1(x) # x
#else
# error "kwsysPrivate.h included multiple times."
#endif
@@ -1,209 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(CommandLineArguments.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "CommandLineArguments.hxx.in"
#endif
#include <iostream>
#include <vector>
#include <stddef.h> /* size_t */
#include <string.h> /* strcmp */
static void* random_ptr = reinterpret_cast<void*>(0x123);
static int argument(const char* arg, const char* value, void* call_data)
{
std::cout << "Got argument: \"" << arg << "\" value: \""
<< (value ? value : "(null)") << "\"" << std::endl;
if (call_data != random_ptr) {
std::cerr << "Problem processing call_data" << std::endl;
return 0;
}
return 1;
}
static int unknown_argument(const char* argument, void* call_data)
{
std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl;
if (call_data != random_ptr) {
std::cerr << "Problem processing call_data" << std::endl;
return 0;
}
return 1;
}
static bool CompareTwoItemsOnList(bool i1, bool i2)
{
return i1 == i2;
}
static bool CompareTwoItemsOnList(int i1, int i2)
{
return i1 == i2;
}
static bool CompareTwoItemsOnList(double i1, double i2)
{
return i1 == i2;
}
static bool CompareTwoItemsOnList(const char* i1, const char* i2)
{
return strcmp(i1, i2) == 0;
}
static bool CompareTwoItemsOnList(const std::string& i1, const std::string& i2)
{
return i1 == i2;
}
int testCommandLineArguments(int argc, char* argv[])
{
// Example run: ./testCommandLineArguments --some-int-variable 4
// --another-bool-variable --some-bool-variable=yes
// --some-stl-string-variable=foobar --set-bool-arg1 --set-bool-arg2
// --some-string-variable=hello
int res = 0;
kwsys::CommandLineArguments arg;
arg.Initialize(argc, argv);
// For error handling
arg.SetClientData(random_ptr);
arg.SetUnknownArgumentCallback(unknown_argument);
int some_int_variable = 10;
double some_double_variable = 10.10;
char* some_string_variable = nullptr;
std::string some_stl_string_variable;
bool some_bool_variable = false;
bool some_bool_variable1 = false;
bool bool_arg1 = false;
int bool_arg2 = 0;
std::vector<int> numbers_argument;
int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 };
std::vector<double> doubles_argument;
double valid_doubles[] = { 12.5, 1.31, 22 };
std::vector<bool> bools_argument;
bool valid_bools[] = { true, true, false };
std::vector<char*> strings_argument;
const char* valid_strings[] = { "andy", "bill", "brad", "ken" };
std::vector<std::string> stl_strings_argument;
std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" };
typedef kwsys::CommandLineArguments argT;
arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT,
&some_int_variable, "Set some random int variable");
arg.AddArgument("--some-double-variable", argT::CONCAT_ARGUMENT,
&some_double_variable, "Set some random double variable");
arg.AddArgument("--some-string-variable", argT::EQUAL_ARGUMENT,
&some_string_variable, "Set some random string variable");
arg.AddArgument("--some-stl-string-variable", argT::EQUAL_ARGUMENT,
&some_stl_string_variable,
"Set some random stl string variable");
arg.AddArgument("--some-bool-variable", argT::EQUAL_ARGUMENT,
&some_bool_variable, "Set some random bool variable");
arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT,
&some_bool_variable1, "Set some random bool variable 1");
arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1,
"Test AddBooleanArgument 1");
arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2,
"Test AddBooleanArgument 2");
arg.AddArgument("--some-multi-argument", argT::MULTI_ARGUMENT,
&numbers_argument, "Some multiple values variable");
arg.AddArgument("-N", argT::SPACE_ARGUMENT, &doubles_argument,
"Some explicit multiple values variable");
arg.AddArgument("-BB", argT::CONCAT_ARGUMENT, &bools_argument,
"Some explicit multiple values variable");
arg.AddArgument("-SS", argT::EQUAL_ARGUMENT, &strings_argument,
"Some explicit multiple values variable");
arg.AddArgument("-SSS", argT::MULTI_ARGUMENT, &stl_strings_argument,
"Some explicit multiple values variable");
arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr,
"Some option -A. This option has a multiline comment. It "
"should demonstrate how the code splits lines.");
arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr,
"Option -B takes argument with space");
arg.AddCallback("-C", argT::EQUAL_ARGUMENT, argument, random_ptr,
"Option -C takes argument after =");
arg.AddCallback("-D", argT::CONCAT_ARGUMENT, argument, random_ptr,
"This option takes concatenated argument");
arg.AddCallback("--long1", argT::NO_ARGUMENT, argument, random_ptr, "-A");
arg.AddCallback("--long2", argT::SPACE_ARGUMENT, argument, random_ptr, "-B");
arg.AddCallback("--long3", argT::EQUAL_ARGUMENT, argument, random_ptr,
"Same as -C but a bit different");
arg.AddCallback("--long4", argT::CONCAT_ARGUMENT, argument, random_ptr,
"-C");
if (!arg.Parse()) {
std::cerr << "Problem parsing arguments" << std::endl;
res = 1;
}
std::cout << "Help: " << arg.GetHelp() << std::endl;
std::cout << "Some int variable was set to: " << some_int_variable
<< std::endl;
std::cout << "Some double variable was set to: " << some_double_variable
<< std::endl;
if (some_string_variable &&
strcmp(some_string_variable, "test string with space") == 0) {
std::cout << "Some string variable was set to: " << some_string_variable
<< std::endl;
delete[] some_string_variable;
} else {
std::cerr << "Problem setting string variable" << std::endl;
res = 1;
}
size_t cc;
#define CompareTwoLists(list1, list_valid, lsize) \
do { \
if (list1.size() != lsize) { \
std::cerr << "Problem setting " #list1 ". Size is: " << list1.size() \
<< " should be: " << lsize << std::endl; \
res = 1; \
} else { \
std::cout << #list1 " argument set:"; \
for (cc = 0; cc < lsize; ++cc) { \
std::cout << " " << list1[cc]; \
if (!CompareTwoItemsOnList(list1[cc], list_valid[cc])) { \
std::cerr << "Problem setting " #list1 ". Value of " << cc \
<< " is: [" << list1[cc] << "] <> [" << list_valid[cc] \
<< "]" << std::endl; \
res = 1; \
break; \
} \
} \
std::cout << std::endl; \
} \
} while (0)
CompareTwoLists(numbers_argument, valid_numbers, 10);
CompareTwoLists(doubles_argument, valid_doubles, 3);
CompareTwoLists(bools_argument, valid_bools, 3);
CompareTwoLists(strings_argument, valid_strings, 4);
CompareTwoLists(stl_strings_argument, valid_stl_strings, 4);
std::cout << "Some STL String variable was set to: "
<< some_stl_string_variable << std::endl;
std::cout << "Some bool variable was set to: " << some_bool_variable
<< std::endl;
std::cout << "Some bool variable was set to: " << some_bool_variable1
<< std::endl;
std::cout << "bool_arg1 variable was set to: " << bool_arg1 << std::endl;
std::cout << "bool_arg2 variable was set to: " << bool_arg2 << std::endl;
std::cout << std::endl;
for (cc = 0; cc < strings_argument.size(); ++cc) {
delete[] strings_argument[cc];
strings_argument[cc] = nullptr;
}
return res;
}
@@ -1,93 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(CommandLineArguments.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "CommandLineArguments.hxx.in"
#endif
#include <iostream>
#include <vector>
#include <assert.h> /* assert */
#include <string.h> /* strcmp */
int testCommandLineArguments1(int argc, char* argv[])
{
kwsys::CommandLineArguments arg;
arg.Initialize(argc, argv);
int n = 0;
char* m = nullptr;
std::string p;
int res = 0;
typedef kwsys::CommandLineArguments argT;
arg.AddArgument("-n", argT::SPACE_ARGUMENT, &n, "Argument N");
arg.AddArgument("-m", argT::EQUAL_ARGUMENT, &m, "Argument M");
arg.AddBooleanArgument("-p", &p, "Argument P");
arg.StoreUnusedArguments(true);
if (!arg.Parse()) {
std::cerr << "Problem parsing arguments" << std::endl;
res = 1;
}
if (n != 24) {
std::cout << "Problem setting N. Value of N: " << n << std::endl;
res = 1;
}
if (!m || strcmp(m, "test value") != 0) {
std::cout << "Problem setting M. Value of M: " << m << std::endl;
res = 1;
}
if (p != "1") {
std::cout << "Problem setting P. Value of P: " << p << std::endl;
res = 1;
}
std::cout << "Value of N: " << n << std::endl;
std::cout << "Value of M: " << m << std::endl;
std::cout << "Value of P: " << p << std::endl;
if (m) {
delete[] m;
}
char** newArgv = nullptr;
int newArgc = 0;
arg.GetUnusedArguments(&newArgc, &newArgv);
int cc;
const char* valid_unused_args[9] = { nullptr,
"--ignored",
"--second-ignored",
"third-ignored",
"some",
"junk",
"at",
"the",
"end" };
if (newArgc != 9) {
std::cerr << "Bad number of unused arguments: " << newArgc << std::endl;
res = 1;
}
for (cc = 0; cc < newArgc; ++cc) {
assert(newArgv[cc]); /* Quiet Clang scan-build. */
std::cout << "Unused argument[" << cc << "] = [" << newArgv[cc] << "]"
<< std::endl;
if (cc >= 9) {
std::cerr << "Too many unused arguments: " << cc << std::endl;
res = 1;
} else if (valid_unused_args[cc] &&
strcmp(valid_unused_args[cc], newArgv[cc]) != 0) {
std::cerr << "Bad unused argument [" << cc << "] \"" << newArgv[cc]
<< "\" should be: \"" << valid_unused_args[cc] << "\""
<< std::endl;
res = 1;
}
}
arg.DeleteRemainingArguments(newArgc, &newArgv);
return res;
}
-30
View File
@@ -1,30 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Configure.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Configure.hxx.in"
#endif
static bool testFallthrough(int n)
{
int r = 0;
switch (n) {
case 1:
++r;
KWSYS_FALLTHROUGH;
default:
++r;
}
return r == 2;
}
int testConfigure(int, char* [])
{
bool res = true;
res = testFallthrough(1) && res;
return res ? 0 : 1;
}
-782
View File
@@ -1,782 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
// Ignore Windows version levels defined by command-line flags. This
// source needs access to all APIs available on the host in order for
// the test to run properly. The test binary is not installed anyway.
#undef _WIN32_WINNT
#undef NTDDI_VERSION
#include KWSYS_HEADER(Encoding.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Encoding.hxx.in"
#endif
#if defined(_WIN32)
# include <algorithm>
# include <iomanip>
# include <iostream>
# include <stdexcept>
# include <string.h>
# include <wchar.h>
# include <windows.h>
# include "testConsoleBuf.hxx"
# if defined(_MSC_VER) && _MSC_VER >= 1800
# define KWSYS_WINDOWS_DEPRECATED_GetVersion
# endif
// يونيكود
static const WCHAR UnicodeInputTestString[] =
L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!";
static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE;
static const DWORD waitTimeout = 10 * 1000;
static STARTUPINFO startupInfo;
static PROCESS_INFORMATION processInfo;
static HANDLE beforeInputEvent;
static HANDLE afterOutputEvent;
static std::string encodedInputTestString;
static std::string encodedTestString;
static void displayError(DWORD errorCode)
{
std::cerr.setf(std::ios::hex, std::ios::basefield);
std::cerr << "Failed with error: 0x" << errorCode << "!" << std::endl;
LPWSTR message;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
nullptr, errorCode, 0, (LPWSTR)&message, 0, nullptr)) {
std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message)
<< std::endl;
HeapFree(GetProcessHeap(), 0, message);
} else {
std::cerr << "FormatMessage() failed with error: 0x" << GetLastError()
<< "!" << std::endl;
}
std::cerr.unsetf(std::ios::hex);
}
std::basic_streambuf<char>* errstream(const char* unused)
{
static_cast<void>(unused);
return std::cerr.rdbuf();
}
std::basic_streambuf<wchar_t>* errstream(const wchar_t* unused)
{
static_cast<void>(unused);
return std::wcerr.rdbuf();
}
template <typename T>
static void dumpBuffers(const T* expected, const T* received, size_t size)
{
std::basic_ostream<T> err(errstream(expected));
err << "Expected output: '" << std::basic_string<T>(expected, size) << "'"
<< std::endl;
if (err.fail()) {
err.clear();
err << "--- Error while outputting ---" << std::endl;
}
err << "Received output: '" << std::basic_string<T>(received, size) << "'"
<< std::endl;
if (err.fail()) {
err.clear();
err << "--- Error while outputting ---" << std::endl;
}
std::cerr << "Expected output | Received output" << std::endl;
for (size_t i = 0; i < size; i++) {
std::cerr << std::setbase(16) << std::setfill('0') << " "
<< "0x" << std::setw(8) << static_cast<unsigned int>(expected[i])
<< " | "
<< "0x" << std::setw(8)
<< static_cast<unsigned int>(received[i]);
if (static_cast<unsigned int>(expected[i]) !=
static_cast<unsigned int>(received[i])) {
std::cerr << " MISMATCH!";
}
std::cerr << std::endl;
}
std::cerr << std::endl;
}
static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr)
{
BOOL bInheritHandles = FALSE;
DWORD dwCreationFlags = 0;
memset(&processInfo, 0, sizeof(processInfo));
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_HIDE;
if (hIn || hOut || hErr) {
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
startupInfo.hStdInput = hIn;
startupInfo.hStdOutput = hOut;
startupInfo.hStdError = hErr;
bInheritHandles = TRUE;
}
WCHAR cmd[MAX_PATH];
if (GetModuleFileNameW(nullptr, cmd, MAX_PATH) == 0) {
std::cerr << "GetModuleFileName failed!" << std::endl;
return false;
}
WCHAR* p = cmd + wcslen(cmd);
while (p > cmd && *p != L'\\')
p--;
*(p + 1) = 0;
wcscat(cmd, cmdConsoleBufChild);
wcscat(cmd, L".exe");
bool success =
CreateProcessW(nullptr, // No module name (use command line)
cmd, // Command line
nullptr, // Process handle not inheritable
nullptr, // Thread handle not inheritable
bInheritHandles, // Set handle inheritance
dwCreationFlags,
nullptr, // Use parent's environment block
nullptr, // Use parent's starting directory
&startupInfo, // Pointer to STARTUPINFO structure
&processInfo) !=
0; // Pointer to PROCESS_INFORMATION structure
if (!success) {
DWORD lastError = GetLastError();
std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) << ")"
<< std::endl;
displayError(lastError);
}
return success;
}
static void finishProcess(bool success)
{
if (success) {
success =
WaitForSingleObject(processInfo.hProcess, waitTimeout) == WAIT_OBJECT_0;
};
if (!success) {
TerminateProcess(processInfo.hProcess, 1);
}
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
static bool createPipe(PHANDLE readPipe, PHANDLE writePipe)
{
SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttributes.bInheritHandle = TRUE;
securityAttributes.lpSecurityDescriptor = nullptr;
return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0 ? false
: true;
}
static void finishPipe(HANDLE readPipe, HANDLE writePipe)
{
if (readPipe != INVALID_HANDLE_VALUE) {
CloseHandle(readPipe);
}
if (writePipe != INVALID_HANDLE_VALUE) {
CloseHandle(writePipe);
}
}
static HANDLE createFile(LPCWSTR fileName)
{
SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttributes.bInheritHandle = TRUE;
securityAttributes.lpSecurityDescriptor = nullptr;
HANDLE file =
CreateFileW(fileName, GENERIC_READ | GENERIC_WRITE,
0, // do not share
&securityAttributes,
CREATE_ALWAYS, // overwrite existing
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
nullptr); // no template
if (file == INVALID_HANDLE_VALUE) {
DWORD lastError = GetLastError();
std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) << ")"
<< std::endl;
displayError(lastError);
}
return file;
}
static void finishFile(HANDLE file)
{
if (file != INVALID_HANDLE_VALUE) {
CloseHandle(file);
}
}
# ifndef MAPVK_VK_TO_VSC
# define MAPVK_VK_TO_VSC (0)
# endif
static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr)
{
inputBuffer[0].EventType = KEY_EVENT;
inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE;
inputBuffer[0].Event.KeyEvent.wRepeatCount = 1;
SHORT keyCode = VkKeyScanW(chr);
if (keyCode == -1) {
// Character can't be entered with current keyboard layout
// Just set any, it doesn't really matter
keyCode = 'K';
}
inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode);
inputBuffer[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(
inputBuffer[0].Event.KeyEvent.wVirtualKeyCode, MAPVK_VK_TO_VSC);
inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr;
inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0;
if ((HIBYTE(keyCode) & 1) == 1) {
inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
}
if ((HIBYTE(keyCode) & 2) == 2) {
inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
}
if ((HIBYTE(keyCode) & 4) == 4) {
inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
}
inputBuffer[1].EventType = inputBuffer[0].EventType;
inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE;
inputBuffer[1].Event.KeyEvent.wRepeatCount = 1;
inputBuffer[1].Event.KeyEvent.wVirtualKeyCode =
inputBuffer[0].Event.KeyEvent.wVirtualKeyCode;
inputBuffer[1].Event.KeyEvent.wVirtualScanCode =
inputBuffer[0].Event.KeyEvent.wVirtualScanCode;
inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar =
inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar;
inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0;
}
static int testPipe()
{
int didFail = 1;
HANDLE inPipeRead = INVALID_HANDLE_VALUE;
HANDLE inPipeWrite = INVALID_HANDLE_VALUE;
HANDLE outPipeRead = INVALID_HANDLE_VALUE;
HANDLE outPipeWrite = INVALID_HANDLE_VALUE;
HANDLE errPipeRead = INVALID_HANDLE_VALUE;
HANDLE errPipeWrite = INVALID_HANDLE_VALUE;
UINT currentCodepage = GetConsoleCP();
char buffer[200];
char buffer2[200];
try {
if (!createPipe(&inPipeRead, &inPipeWrite) ||
!createPipe(&outPipeRead, &outPipeWrite) ||
!createPipe(&errPipeRead, &errPipeWrite)) {
throw std::runtime_error("createFile failed!");
}
if (TestCodepage == CP_ACP) {
TestCodepage = GetACP();
}
if (!SetConsoleCP(TestCodepage)) {
throw std::runtime_error("SetConsoleCP failed!");
}
DWORD bytesWritten = 0;
if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(),
(DWORD)encodedInputTestString.size(), &bytesWritten,
nullptr) ||
bytesWritten == 0) {
throw std::runtime_error("WriteFile failed!");
}
if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) {
try {
DWORD status;
if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
WAIT_OBJECT_0) {
std::cerr.setf(std::ios::hex, std::ios::basefield);
std::cerr << "WaitForSingleObject returned unexpected status 0x"
<< status << std::endl;
std::cerr.unsetf(std::ios::hex);
throw std::runtime_error("WaitForSingleObject failed!");
}
DWORD bytesRead = 0;
if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead,
nullptr) ||
bytesRead == 0) {
throw std::runtime_error("ReadFile#1 failed!");
}
buffer[bytesRead] = 0;
if ((bytesRead <
encodedTestString.size() + 1 + encodedInputTestString.size() &&
!ReadFile(outPipeRead, buffer + bytesRead,
sizeof(buffer) - bytesRead, &bytesRead, nullptr)) ||
bytesRead == 0) {
throw std::runtime_error("ReadFile#2 failed!");
}
if (memcmp(buffer, encodedTestString.c_str(),
encodedTestString.size()) == 0 &&
memcmp(buffer + encodedTestString.size() + 1,
encodedInputTestString.c_str(),
encodedInputTestString.size()) == 0) {
bytesRead = 0;
if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead,
nullptr) ||
bytesRead == 0) {
throw std::runtime_error("ReadFile#3 failed!");
}
buffer2[bytesRead] = 0;
didFail = encodedTestString.compare(0, std::string::npos, buffer2,
encodedTestString.size()) == 0
? 0
: 1;
}
if (didFail != 0) {
std::cerr << "Pipe's output didn't match expected output!"
<< std::endl;
dumpBuffers<char>(encodedTestString.c_str(), buffer,
encodedTestString.size());
dumpBuffers<char>(encodedInputTestString.c_str(),
buffer + encodedTestString.size() + 1,
encodedInputTestString.size());
dumpBuffers<char>(encodedTestString.c_str(), buffer2,
encodedTestString.size());
}
} catch (const std::runtime_error& ex) {
DWORD lastError = GetLastError();
std::cerr << "In function testPipe, line " << __LINE__ << ": "
<< ex.what() << std::endl;
displayError(lastError);
}
finishProcess(didFail == 0);
}
} catch (const std::runtime_error& ex) {
DWORD lastError = GetLastError();
std::cerr << "In function testPipe, line " << __LINE__ << ": " << ex.what()
<< std::endl;
displayError(lastError);
}
finishPipe(inPipeRead, inPipeWrite);
finishPipe(outPipeRead, outPipeWrite);
finishPipe(errPipeRead, errPipeWrite);
SetConsoleCP(currentCodepage);
return didFail;
}
static int testFile()
{
int didFail = 1;
HANDLE inFile = INVALID_HANDLE_VALUE;
HANDLE outFile = INVALID_HANDLE_VALUE;
HANDLE errFile = INVALID_HANDLE_VALUE;
try {
if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE ||
(outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE ||
(errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) {
throw std::runtime_error("createFile failed!");
}
DWORD bytesWritten = 0;
char buffer[200];
char buffer2[200];
int length;
if ((length = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString,
-1, buffer, sizeof(buffer), nullptr,
nullptr)) == 0) {
throw std::runtime_error("WideCharToMultiByte failed!");
}
buffer[length - 1] = '\n';
if (!WriteFile(inFile, buffer, length, &bytesWritten, nullptr) ||
bytesWritten == 0) {
throw std::runtime_error("WriteFile failed!");
}
if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
throw std::runtime_error("SetFilePointer failed!");
}
if (createProcess(inFile, outFile, errFile)) {
DWORD bytesRead = 0;
try {
DWORD status;
if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
WAIT_OBJECT_0) {
std::cerr.setf(std::ios::hex, std::ios::basefield);
std::cerr << "WaitForSingleObject returned unexpected status 0x"
<< status << std::endl;
std::cerr.unsetf(std::ios::hex);
throw std::runtime_error("WaitForSingleObject failed!");
}
if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER) {
throw std::runtime_error("SetFilePointer#1 failed!");
}
if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, nullptr) ||
bytesRead == 0) {
throw std::runtime_error("ReadFile#1 failed!");
}
buffer[bytesRead] = 0;
if (memcmp(buffer, encodedTestString.c_str(),
encodedTestString.size()) == 0 &&
memcmp(buffer + encodedTestString.size() + 1,
encodedInputTestString.c_str(),
encodedInputTestString.size()) == 0) {
bytesRead = 0;
if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER) {
throw std::runtime_error("SetFilePointer#2 failed!");
}
if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead,
nullptr) ||
bytesRead == 0) {
throw std::runtime_error("ReadFile#2 failed!");
}
buffer2[bytesRead] = 0;
didFail = encodedTestString.compare(0, std::string::npos, buffer2,
encodedTestString.size()) == 0
? 0
: 1;
}
if (didFail != 0) {
std::cerr << "File's output didn't match expected output!"
<< std::endl;
dumpBuffers<char>(encodedTestString.c_str(), buffer,
encodedTestString.size());
dumpBuffers<char>(encodedInputTestString.c_str(),
buffer + encodedTestString.size() + 1,
encodedInputTestString.size());
dumpBuffers<char>(encodedTestString.c_str(), buffer2,
encodedTestString.size());
}
} catch (const std::runtime_error& ex) {
DWORD lastError = GetLastError();
std::cerr << "In function testFile, line " << __LINE__ << ": "
<< ex.what() << std::endl;
displayError(lastError);
}
finishProcess(didFail == 0);
}
} catch (const std::runtime_error& ex) {
DWORD lastError = GetLastError();
std::cerr << "In function testFile, line " << __LINE__ << ": " << ex.what()
<< std::endl;
displayError(lastError);
}
finishFile(inFile);
finishFile(outFile);
finishFile(errFile);
return didFail;
}
# ifndef _WIN32_WINNT_VISTA
# define _WIN32_WINNT_VISTA 0x0600
# endif
static int testConsole()
{
int didFail = 1;
HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE);
HANDLE hIn = parentIn;
HANDLE hOut = parentOut;
DWORD consoleMode;
bool newConsole = false;
bool forceNewConsole = false;
bool restoreConsole = false;
LPCWSTR TestFaceName = L"Lucida Console";
const DWORD TestFontFamily = 0x00000036;
const DWORD TestFontSize = 0x000c0000;
HKEY hConsoleKey;
WCHAR FaceName[200];
FaceName[0] = 0;
DWORD FaceNameSize = sizeof(FaceName);
DWORD FontFamily = TestFontFamily;
DWORD FontSize = TestFontSize;
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
# pragma warning(push)
# ifdef __INTEL_COMPILER
# pragma warning(disable : 1478)
# elif defined __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma warning(disable : 4996)
# endif
# endif
const bool isVistaOrGreater =
LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
# ifdef __clang__
# pragma clang diagnostic pop
# else
# pragma warning(pop)
# endif
# endif
if (!isVistaOrGreater) {
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
&hConsoleKey) == ERROR_SUCCESS) {
DWORD dwordSize = sizeof(DWORD);
if (RegQueryValueExW(hConsoleKey, L"FontFamily", nullptr, nullptr,
(LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) {
if (FontFamily != TestFontFamily) {
RegQueryValueExW(hConsoleKey, L"FaceName", nullptr, nullptr,
(LPBYTE)FaceName, &FaceNameSize);
RegQueryValueExW(hConsoleKey, L"FontSize", nullptr, nullptr,
(LPBYTE)&FontSize, &dwordSize);
RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
(BYTE*)&TestFontFamily, sizeof(TestFontFamily));
RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
(BYTE*)TestFaceName,
(DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR)));
RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
(BYTE*)&TestFontSize, sizeof(TestFontSize));
restoreConsole = true;
forceNewConsole = true;
}
} else {
std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl;
}
RegCloseKey(hConsoleKey);
} else {
std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!"
<< std::endl;
}
}
if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) {
// Not a real console, let's create new one.
FreeConsole();
if (!AllocConsole()) {
std::cerr << "AllocConsole failed!" << std::endl;
return didFail;
}
SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttributes.bInheritHandle = TRUE;
securityAttributes.lpSecurityDescriptor = nullptr;
hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
OPEN_EXISTING, 0, nullptr);
if (hIn == INVALID_HANDLE_VALUE) {
DWORD lastError = GetLastError();
std::cerr << "CreateFile(CONIN$)" << std::endl;
displayError(lastError);
}
hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
OPEN_EXISTING, 0, nullptr);
if (hOut == INVALID_HANDLE_VALUE) {
DWORD lastError = GetLastError();
std::cerr << "CreateFile(CONOUT$)" << std::endl;
displayError(lastError);
}
SetStdHandle(STD_INPUT_HANDLE, hIn);
SetStdHandle(STD_OUTPUT_HANDLE, hOut);
SetStdHandle(STD_ERROR_HANDLE, hOut);
newConsole = true;
}
# if _WIN32_WINNT >= _WIN32_WINNT_VISTA
if (isVistaOrGreater) {
CONSOLE_FONT_INFOEX consoleFont;
memset(&consoleFont, 0, sizeof(consoleFont));
consoleFont.cbSize = sizeof(consoleFont);
HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
typedef BOOL(WINAPI * GetCurrentConsoleFontExFunc)(
HANDLE hConsoleOutput, BOOL bMaximumWindow,
PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
typedef BOOL(WINAPI * SetCurrentConsoleFontExFunc)(
HANDLE hConsoleOutput, BOOL bMaximumWindow,
PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
GetCurrentConsoleFontExFunc getConsoleFont =
(GetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
"GetCurrentConsoleFontEx");
SetCurrentConsoleFontExFunc setConsoleFont =
(SetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
"SetCurrentConsoleFontEx");
if (getConsoleFont(hOut, FALSE, &consoleFont)) {
if (consoleFont.FontFamily != TestFontFamily) {
consoleFont.FontFamily = TestFontFamily;
wcscpy(consoleFont.FaceName, TestFaceName);
if (!setConsoleFont(hOut, FALSE, &consoleFont)) {
std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl;
}
}
} else {
std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl;
}
} else {
# endif
if (restoreConsole &&
RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_WRITE,
&hConsoleKey) == ERROR_SUCCESS) {
RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
(BYTE*)&FontFamily, sizeof(FontFamily));
if (FaceName[0] != 0) {
RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, (BYTE*)FaceName,
FaceNameSize);
} else {
RegDeleteValueW(hConsoleKey, L"FaceName");
}
RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE*)&FontSize,
sizeof(FontSize));
RegCloseKey(hConsoleKey);
}
# if _WIN32_WINNT >= _WIN32_WINNT_VISTA
}
# endif
if (createProcess(nullptr, nullptr, nullptr)) {
try {
DWORD status;
if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) !=
WAIT_OBJECT_0) {
std::cerr.setf(std::ios::hex, std::ios::basefield);
std::cerr << "WaitForSingleObject returned unexpected status 0x"
<< status << std::endl;
std::cerr.unsetf(std::ios::hex);
throw std::runtime_error("WaitForSingleObject#1 failed!");
}
INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) /
sizeof(UnicodeInputTestString[0])) *
2];
memset(&inputBuffer, 0, sizeof(inputBuffer));
unsigned int i;
for (i = 0; i < (sizeof(UnicodeInputTestString) /
sizeof(UnicodeInputTestString[0]) -
1);
i++) {
writeInputKeyEvent(&inputBuffer[i * 2], UnicodeInputTestString[i]);
}
writeInputKeyEvent(&inputBuffer[i * 2], VK_RETURN);
DWORD eventsWritten = 0;
// We need to wait a bit before writing to console so child process have
// started waiting for input on stdin.
Sleep(300);
if (!WriteConsoleInputW(hIn, inputBuffer,
sizeof(inputBuffer) / sizeof(inputBuffer[0]),
&eventsWritten) ||
eventsWritten == 0) {
throw std::runtime_error("WriteConsoleInput failed!");
}
if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
WAIT_OBJECT_0) {
std::cerr.setf(std::ios::hex, std::ios::basefield);
std::cerr << "WaitForSingleObject returned unexpected status 0x"
<< status << std::endl;
std::cerr.unsetf(std::ios::hex);
throw std::runtime_error("WaitForSingleObject#2 failed!");
}
CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) {
throw std::runtime_error("GetConsoleScreenBufferInfo failed!");
}
COORD coord;
DWORD charsRead = 0;
coord.X = 0;
coord.Y = screenBufferInfo.dwCursorPosition.Y - 4;
WCHAR* outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4];
if (!ReadConsoleOutputCharacterW(hOut, outputBuffer,
screenBufferInfo.dwSize.X * 4, coord,
&charsRead) ||
charsRead == 0) {
delete[] outputBuffer;
throw std::runtime_error("ReadConsoleOutputCharacter failed!");
}
std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString);
std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' ');
std::wstring wideInputTestString =
kwsys::Encoding::ToWide(encodedInputTestString);
if (memcmp(outputBuffer, wideTestString.c_str(),
wideTestString.size() * sizeof(wchar_t)) == 0 &&
memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1,
wideTestString.c_str(),
wideTestString.size() * sizeof(wchar_t)) == 0 &&
memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2,
UnicodeInputTestString,
sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 &&
memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3,
wideInputTestString.c_str(),
(wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0) {
didFail = 0;
} else {
std::cerr << "Console's output didn't match expected output!"
<< std::endl;
dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer,
wideTestString.size());
dumpBuffers<wchar_t>(wideTestString.c_str(),
outputBuffer + screenBufferInfo.dwSize.X * 1,
wideTestString.size());
dumpBuffers<wchar_t>(
UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2,
(sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR));
dumpBuffers<wchar_t>(wideInputTestString.c_str(),
outputBuffer + screenBufferInfo.dwSize.X * 3,
wideInputTestString.size() - 1);
}
delete[] outputBuffer;
} catch (const std::runtime_error& ex) {
DWORD lastError = GetLastError();
std::cerr << "In function testConsole, line " << __LINE__ << ": "
<< ex.what() << std::endl;
displayError(lastError);
}
finishProcess(didFail == 0);
}
if (newConsole) {
SetStdHandle(STD_INPUT_HANDLE, parentIn);
SetStdHandle(STD_OUTPUT_HANDLE, parentOut);
SetStdHandle(STD_ERROR_HANDLE, parentErr);
CloseHandle(hIn);
CloseHandle(hOut);
FreeConsole();
}
return didFail;
}
#endif
int testConsoleBuf(int, char* [])
{
int ret = 0;
#if defined(_WIN32)
beforeInputEvent = CreateEventW(nullptr,
FALSE, // auto-reset event
FALSE, // initial state is nonsignaled
BeforeInputEventName); // object name
if (!beforeInputEvent) {
std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl;
return 1;
}
afterOutputEvent = CreateEventW(nullptr, FALSE, FALSE, AfterOutputEventName);
if (!afterOutputEvent) {
std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl;
return 1;
}
encodedTestString = kwsys::Encoding::ToNarrow(std::wstring(
UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1));
encodedInputTestString = kwsys::Encoding::ToNarrow(
std::wstring(UnicodeInputTestString,
sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1));
encodedInputTestString += "\n";
ret |= testPipe();
ret |= testFile();
ret |= testConsole();
CloseHandle(beforeInputEvent);
CloseHandle(afterOutputEvent);
#endif
return ret;
}
-17
View File
@@ -1,17 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifndef testConsoleBuf_hxx
#define testConsoleBuf_hxx
static const wchar_t cmdConsoleBufChild[] = L"testConsoleBufChild";
static const wchar_t BeforeInputEventName[] = L"BeforeInputEvent";
static const wchar_t AfterOutputEventName[] = L"AfterOutputEvent";
// यूनिकोड είναι здорово!
static const wchar_t UnicodeTestString[] =
L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 "
L"\u03B5\u03AF\u03BD\0\u03B1\u03B9 "
L"\u0437\u0434\u043E\u0440\u043E\u0432\u043E!";
#endif
@@ -1,55 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(ConsoleBuf.hxx)
#include KWSYS_HEADER(Encoding.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "ConsoleBuf.hxx.in"
# include "Encoding.hxx.in"
#endif
#include <iostream>
#include "testConsoleBuf.hxx"
int main(int argc, const char* argv[])
{
#if defined(_WIN32)
kwsys::ConsoleBuf::Manager out(std::cout);
kwsys::ConsoleBuf::Manager err(std::cerr, true);
kwsys::ConsoleBuf::Manager in(std::cin);
if (argc > 1) {
std::cout << argv[1] << std::endl;
std::cerr << argv[1] << std::endl;
} else {
std::string str = kwsys::Encoding::ToNarrow(std::wstring(
UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1));
std::cout << str << std::endl;
std::cerr << str << std::endl;
}
std::string input;
HANDLE event = OpenEventW(EVENT_MODIFY_STATE, FALSE, BeforeInputEventName);
if (event) {
SetEvent(event);
CloseHandle(event);
}
std::cin >> input;
std::cout << input << std::endl;
event = OpenEventW(EVENT_MODIFY_STATE, FALSE, AfterOutputEventName);
if (event) {
SetEvent(event);
CloseHandle(event);
}
#else
static_cast<void>(argc);
static_cast<void>(argv);
#endif
return 0;
}
-110
View File
@@ -1,110 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Directory.hxx)
#include KWSYS_HEADER(Encoding.hxx)
#include KWSYS_HEADER(SystemTools.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Directory.hxx.in"
# include "Encoding.hxx.in"
# include "SystemTools.hxx.in"
#endif
#include <fstream>
#include <iostream>
#include <sstream>
#include <testSystemTools.h>
int _doLongPathTest()
{
using namespace kwsys;
static const int LONG_PATH_THRESHOLD = 512;
int res = 0;
std::string topdir(TEST_SYSTEMTOOLS_BINARY_DIR "/directory_testing/");
std::stringstream testpathstrm;
std::string testdirpath;
std::string extendedtestdirpath;
testpathstrm << topdir;
size_t pathlen = testpathstrm.str().length();
testpathstrm.seekp(0, std::ios_base::end);
while (pathlen < LONG_PATH_THRESHOLD) {
testpathstrm << "0123456789/";
pathlen = testpathstrm.str().length();
}
testdirpath = testpathstrm.str();
#ifdef _WIN32
extendedtestdirpath =
Encoding::ToNarrow(SystemTools::ConvertToWindowsExtendedPath(testdirpath));
#else
extendedtestdirpath = testdirpath;
#endif
if (SystemTools::MakeDirectory(extendedtestdirpath)) {
std::ofstream testfile1(
(extendedtestdirpath + "longfilepathtest1.txt").c_str());
std::ofstream testfile2(
(extendedtestdirpath + "longfilepathtest2.txt").c_str());
testfile1 << "foo";
testfile2 << "bar";
testfile1.close();
testfile2.close();
Directory testdir;
// Set res to failure if the directory doesn't load
res += !testdir.Load(testdirpath);
// Increment res failure if the directory appears empty
res += testdir.GetNumberOfFiles() == 0;
// Increment res failures if the path has changed from
// what was provided.
res += testdirpath != testdir.GetPath();
SystemTools::RemoveADirectory(topdir);
} else {
std::cerr << "Failed to create directory with long path: "
<< extendedtestdirpath << std::endl;
res += 1;
}
return res;
}
int _copyDirectoryTest()
{
using namespace kwsys;
const std::string source(TEST_SYSTEMTOOLS_BINARY_DIR
"/directory_testing/copyDirectoryTestSrc");
if (SystemTools::PathExists(source)) {
std::cerr << source << " shouldn't exist before test" << std::endl;
return 1;
}
const std::string destination(TEST_SYSTEMTOOLS_BINARY_DIR
"/directory_testing/copyDirectoryTestDst");
if (SystemTools::PathExists(destination)) {
std::cerr << destination << " shouldn't exist before test" << std::endl;
return 2;
}
const bool copysuccess = SystemTools::CopyADirectory(source, destination);
const bool destinationexists = SystemTools::PathExists(destination);
if (copysuccess) {
std::cerr << "CopyADirectory should have returned false" << std::endl;
SystemTools::RemoveADirectory(destination);
return 3;
}
if (destinationexists) {
std::cerr << "CopyADirectory returned false, but destination directory"
<< " has been created" << std::endl;
SystemTools::RemoveADirectory(destination);
return 4;
}
return 0;
}
int testDirectory(int, char* [])
{
return _doLongPathTest() + _copyDirectoryTest();
}
-133
View File
@@ -1,133 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(DynamicLoader.hxx)
#if defined(__BEOS__) || defined(__HAIKU__)
# include <be/kernel/OS.h> /* disable_debugger() API. */
#endif
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "DynamicLoader.hxx.in"
#endif
#include <iostream>
#include <string>
// Include with <> instead of "" to avoid getting any in-source copy
// left on disk.
#include <testSystemTools.h>
static std::string GetLibName(const char* lname, const char* subdir = nullptr)
{
// Construct proper name of lib
std::string slname;
slname = EXECUTABLE_OUTPUT_PATH;
if (subdir) {
slname += "/";
slname += subdir;
}
#ifdef CMAKE_INTDIR
slname += "/";
slname += CMAKE_INTDIR;
#endif
slname += "/";
slname += kwsys::DynamicLoader::LibPrefix();
slname += lname;
slname += kwsys::DynamicLoader::LibExtension();
return slname;
}
/* libname = Library name (proper prefix, proper extension)
* System = symbol to lookup in libname
* r1: should OpenLibrary succeed ?
* r2: should GetSymbolAddress succeed ?
* r3: should CloseLibrary succeed ?
*/
static int TestDynamicLoader(const char* libname, const char* symbol, int r1,
int r2, int r3, int flags = 0)
{
std::cerr << "Testing: " << libname << std::endl;
kwsys::DynamicLoader::LibraryHandle l =
kwsys::DynamicLoader::OpenLibrary(libname, flags);
// If result is incompatible with expectation just fails (xor):
if ((r1 && !l) || (!r1 && l)) {
std::cerr << "OpenLibrary: " << kwsys::DynamicLoader::LastError()
<< std::endl;
return 1;
}
kwsys::DynamicLoader::SymbolPointer f =
kwsys::DynamicLoader::GetSymbolAddress(l, symbol);
if ((r2 && !f) || (!r2 && f)) {
std::cerr << "GetSymbolAddress: " << kwsys::DynamicLoader::LastError()
<< std::endl;
return 1;
}
#ifndef __APPLE__
int s = kwsys::DynamicLoader::CloseLibrary(l);
if ((r3 && !s) || (!r3 && s)) {
std::cerr << "CloseLibrary: " << kwsys::DynamicLoader::LastError()
<< std::endl;
return 1;
}
#else
(void)r3;
#endif
return 0;
}
int testDynamicLoader(int argc, char* argv[])
{
#if defined(_WIN32)
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
#elif defined(__BEOS__) || defined(__HAIKU__)
disable_debugger(1);
#endif
int res = 0;
if (argc == 3) {
// User specify a libname and symbol to check.
res = TestDynamicLoader(argv[1], argv[2], 1, 1, 1);
return res;
}
// dlopen() on Syllable before 11/22/2007 doesn't return 0 on error
#ifndef __SYLLABLE__
// Make sure that inexistent lib is giving correct result
res += TestDynamicLoader("azerty_", "foo_bar", 0, 0, 0);
// Make sure that random binary file cannot be assimilated as dylib
res += TestDynamicLoader(TEST_SYSTEMTOOLS_SOURCE_DIR "/testSystemTools.bin",
"wp", 0, 0, 0);
#endif
#ifdef __linux__
// This one is actually fun to test, since dlopen is by default
// loaded...wonder why :)
res += TestDynamicLoader("foobar.lib", "dlopen", 0, 1, 0);
res += TestDynamicLoader("libdl.so", "dlopen", 1, 1, 1);
res += TestDynamicLoader("libdl.so", "TestDynamicLoader", 1, 0, 1);
#endif
// Now try on the generated library
std::string libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynload");
res += TestDynamicLoader(libname.c_str(), "dummy", 1, 0, 1);
res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderSymbolPointer",
1, 1, 1);
res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderSymbolPointer",
1, 0, 1);
res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1);
res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1);
#ifdef _WIN32
libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynloadUse", "dynloaddir");
res += TestDynamicLoader(libname.c_str(), "dummy", 0, 0, 0);
res += TestDynamicLoader(libname.c_str(), "TestLoad", 1, 1, 1,
kwsys::DynamicLoader::SearchBesideLibrary);
res += TestDynamicLoader(libname.c_str(), "_TestLoad", 1, 0, 1,
kwsys::DynamicLoader::SearchBesideLibrary);
#endif
return res;
}
-13
View File
@@ -1,13 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifdef _WIN32
# define DL_EXPORT __declspec(dllexport)
#else
# define DL_EXPORT
#endif
DL_EXPORT int TestDynamicLoaderData = 0;
DL_EXPORT void TestDynamicLoaderSymbolPointer()
{
}
-10
View File
@@ -1,10 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "testDynloadImpl.h"
int TestDynamicLoaderImplData = 0;
void TestDynamicLoaderImplSymbolPointer()
{
}
-15
View File
@@ -1,15 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#ifdef _WIN32
# ifdef BUILDING_TestDynloadImpl
# define DLIMPL_EXPORT __declspec(dllexport)
# else
# define DLIMPL_EXPORT __declspec(dllimport)
# endif
#else
# define DLIMPL_EXPORT
#endif
DLIMPL_EXPORT int TestDynamicLoaderImplData;
DLIMPL_EXPORT void TestDynamicLoaderImplSymbolPointer();
-15
View File
@@ -1,15 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "testDynloadImpl.h"
#ifdef _WIN32
# define DL_EXPORT __declspec(dllexport)
#else
# define DL_EXPORT
#endif
DL_EXPORT int TestLoad()
{
TestDynamicLoaderImplSymbolPointer();
return TestDynamicLoaderImplData;
}
-67
View File
@@ -1,67 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#include KWSYS_HEADER(MD5.h)
/* Work-around CMake dependency scanning limitation. This must
duplicate the above list of headers. */
#if 0
# include "MD5.h.in"
#endif
#include <stdio.h>
#include <string.h>
static const unsigned char testMD5input1[] =
" A quick brown fox jumps over the lazy dog.\n"
" This is sample text for MD5 sum input.\n";
static const char testMD5output1[] = "8f146af46ed4f267921bb937d4d3500c";
static const int testMD5input2len = 28;
static const unsigned char testMD5input2[] = "the cow jumped over the moon";
static const char testMD5output2[] = "a2ad137b746138fae4e5adca9c85d3ae";
static int testMD5_1(kwsysMD5* md5)
{
char md5out[33];
kwsysMD5_Initialize(md5);
kwsysMD5_Append(md5, testMD5input1, -1);
kwsysMD5_FinalizeHex(md5, md5out);
md5out[32] = 0;
printf("md5sum 1: expected [%s]\n"
" got [%s]\n",
testMD5output1, md5out);
return (strcmp(md5out, testMD5output1) != 0) ? 1 : 0;
}
static int testMD5_2(kwsysMD5* md5)
{
unsigned char digest[16];
char md5out[33];
kwsysMD5_Initialize(md5);
kwsysMD5_Append(md5, testMD5input2, testMD5input2len);
kwsysMD5_Finalize(md5, digest);
kwsysMD5_DigestToHex(digest, md5out);
md5out[32] = 0;
printf("md5sum 2: expected [%s]\n"
" got [%s]\n",
testMD5output2, md5out);
return (strcmp(md5out, testMD5output2) != 0) ? 1 : 0;
}
int testEncode(int argc, char* argv[])
{
int result = 0;
(void)argc;
(void)argv;
/* Test MD5 digest. */
{
kwsysMD5* md5 = kwsysMD5_New();
result |= testMD5_1(md5);
result |= testMD5_2(md5);
kwsysMD5_Delete(md5);
}
return result;
}
-286
View File
@@ -1,286 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#if defined(_MSC_VER)
# pragma warning(disable : 4786)
#endif
#include KWSYS_HEADER(Encoding.hxx)
#include KWSYS_HEADER(Encoding.h)
#include <algorithm>
#include <iostream>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "Encoding.h.in"
# include "Encoding.hxx.in"
#endif
static const unsigned char helloWorldStrings[][32] = {
// English
{ 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 0 },
// Japanese
{ 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0xAB, 0xE3, 0x81,
0xA1, 0xE3, 0x81, 0xAF, 0xE4, 0xB8, 0x96, 0xE7, 0x95, 0x8C, 0 },
// Arabic
{ 0xD9, 0x85, 0xD8, 0xB1, 0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xA7, 0x20, 0xD8,
0xA7, 0xD9, 0x84, 0xD8, 0xB9, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x85, 0 },
// Yiddish
{ 0xD7, 0x94, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x90, 0x20, 0xD7,
0x95, 0xD7, 0x95, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x98, 0 },
// Russian
{ 0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0, 0xB5,
0xD1, 0x82, 0x20, 0xD0, 0xBC, 0xD0, 0xB8, 0xD1, 0x80, 0 },
// Latin
{ 0x4D, 0x75, 0x6E, 0x64, 0x75, 0x73, 0x20, 0x73, 0x61, 0x6C, 0x76, 0x65,
0 },
// Swahili
{ 0x68, 0x75, 0x6A, 0x61, 0x6D, 0x62, 0x6F, 0x20, 0x44, 0x75, 0x6E, 0x69,
0x61, 0 },
// Icelandic
{ 0x48, 0x61, 0x6C, 0x6C, 0xC3, 0xB3, 0x20, 0x68, 0x65, 0x69, 0x6D, 0x75,
0x72, 0 },
{ 0 }
};
static int testHelloWorldEncoding()
{
int ret = 0;
for (int i = 0; helloWorldStrings[i][0] != 0; i++) {
std::string str = reinterpret_cast<const char*>(helloWorldStrings[i]);
std::cout << str << std::endl;
std::wstring wstr = kwsys::Encoding::ToWide(str);
std::string str2 = kwsys::Encoding::ToNarrow(wstr);
wchar_t* c_wstr = kwsysEncoding_DupToWide(str.c_str());
char* c_str2 = kwsysEncoding_DupToNarrow(c_wstr);
if (!wstr.empty() && (str != str2 || strcmp(c_str2, str.c_str()))) {
std::cout << "converted string was different: " << str2 << std::endl;
std::cout << "converted string was different: " << c_str2 << std::endl;
ret++;
}
free(c_wstr);
free(c_str2);
}
return ret;
}
static int testRobustEncoding()
{
// test that the conversion functions handle invalid
// unicode correctly/gracefully
// we manipulate the format flags of stdout, remember
// the original state here to restore before return
std::ios::fmtflags const& flags = std::cout.flags();
int ret = 0;
char cstr[] = { (char)-1, 0 };
// this conversion could fail
std::wstring wstr = kwsys::Encoding::ToWide(cstr);
wstr = kwsys::Encoding::ToWide(nullptr);
if (wstr != L"") {
const wchar_t* wcstr = wstr.c_str();
std::cout << "ToWide(NULL) returned";
for (size_t i = 0; i < wstr.size(); i++) {
std::cout << " " << std::hex << (int)wcstr[i];
}
std::cout << std::endl;
ret++;
}
wstr = kwsys::Encoding::ToWide("");
if (wstr != L"") {
const wchar_t* wcstr = wstr.c_str();
std::cout << "ToWide(\"\") returned";
for (size_t i = 0; i < wstr.size(); i++) {
std::cout << " " << std::hex << (int)wcstr[i];
}
std::cout << std::endl;
ret++;
}
#ifdef _WIN32
// 16 bit wchar_t - we make an invalid surrogate pair
wchar_t cwstr[] = { 0xD801, 0xDA00, 0 };
// this conversion could fail
std::string win_str = kwsys::Encoding::ToNarrow(cwstr);
#endif
std::string str = kwsys::Encoding::ToNarrow(nullptr);
if (str != "") {
std::cout << "ToNarrow(NULL) returned " << str << std::endl;
ret++;
}
str = kwsys::Encoding::ToNarrow(L"");
if (wstr != L"") {
std::cout << "ToNarrow(\"\") returned " << str << std::endl;
ret++;
}
std::cout.flags(flags);
return ret;
}
static int testWithNulls()
{
int ret = 0;
std::vector<std::string> strings;
strings.push_back(std::string("ab") + '\0' + 'c');
strings.push_back(std::string("d") + '\0' + '\0' + 'e');
strings.push_back(std::string() + '\0' + 'f');
strings.push_back(std::string() + '\0' + '\0' + "gh");
strings.push_back(std::string("ij") + '\0');
strings.push_back(std::string("k") + '\0' + '\0');
strings.push_back(std::string("\0\0\0\0", 4) + "lmn" +
std::string("\0\0\0\0", 4));
for (std::vector<std::string>::iterator it = strings.begin();
it != strings.end(); ++it) {
std::wstring wstr = kwsys::Encoding::ToWide(*it);
std::string str = kwsys::Encoding::ToNarrow(wstr);
std::string s(*it);
std::replace(s.begin(), s.end(), '\0', ' ');
std::cout << "'" << s << "' (" << it->size() << ")" << std::endl;
if (str != *it) {
std::replace(str.begin(), str.end(), '\0', ' ');
std::cout << "string with null was different: '" << str << "' ("
<< str.size() << ")" << std::endl;
ret++;
}
}
return ret;
}
static int testCommandLineArguments()
{
int status = 0;
char const* argv[2] = { "./app.exe", (char const*)helloWorldStrings[1] };
kwsys::Encoding::CommandLineArguments args(2, argv);
kwsys::Encoding::CommandLineArguments arg2 =
kwsys::Encoding::CommandLineArguments(args);
char const* const* u8_argv = args.argv();
for (int i = 0; i < args.argc(); i++) {
char const* u8_arg = u8_argv[i];
if (strcmp(argv[i], u8_arg) != 0) {
std::cout << "argv[" << i << "] " << argv[i] << " != " << u8_arg
<< std::endl;
status++;
}
}
kwsys::Encoding::CommandLineArguments args3 =
kwsys::Encoding::CommandLineArguments::Main(2, argv);
return status;
}
static int testToWindowsExtendedPath()
{
#ifdef _WIN32
int ret = 0;
if (kwsys::Encoding::ToWindowsExtendedPath(
"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
<< std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath(
"L:/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath(
"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") !=
L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\""
<< std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath(
"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\""
<< std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath("//") != L"//") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"//\"" << std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\") != L"\\\\.\\") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"\\\\.\\\"" << std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X") != L"\\\\.\\X") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"\\\\.\\X\"" << std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:") != L"\\\\?\\X:") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"\\\\.\\X:\"" << std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:\\") !=
L"\\\\?\\X:\\") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"\\\\.\\X:\\\"" << std::endl;
++ret;
}
if (kwsys::Encoding::ToWindowsExtendedPath("NUL") != L"\\\\.\\NUL") {
std::cout << "Problem with ToWindowsExtendedPath "
<< "\"NUL\"" << std::endl;
++ret;
}
return ret;
#else
return 0;
#endif
}
int testEncoding(int, char* [])
{
const char* loc = setlocale(LC_ALL, "");
if (loc) {
std::cout << "Locale: " << loc << std::endl;
} else {
std::cout << "Locale: None" << std::endl;
}
int ret = 0;
ret |= testHelloWorldEncoding();
ret |= testRobustEncoding();
ret |= testCommandLineArguments();
ret |= testWithNulls();
ret |= testToWindowsExtendedPath();
return ret;
}
-113
View File
@@ -1,113 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include "kwsysPrivate.h"
#if defined(_MSC_VER)
# pragma warning(disable : 4786)
#endif
#include KWSYS_HEADER(FStream.hxx)
#include <string.h>
#ifdef __BORLANDC__
# include <mem.h> /* memcmp */
#endif
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "FStream.hxx.in"
#endif
#include <iostream>
static int testNoFile()
{
kwsys::ifstream in_file("NoSuchFile.txt");
if (in_file) {
return 1;
}
return 0;
}
static const int num_test_files = 7;
static const int max_test_file_size = 45;
static kwsys::FStream::BOM expected_bom[num_test_files] = {
kwsys::FStream::BOM_None, kwsys::FStream::BOM_None,
kwsys::FStream::BOM_UTF8, kwsys::FStream::BOM_UTF16LE,
kwsys::FStream::BOM_UTF16BE, kwsys::FStream::BOM_UTF32LE,
kwsys::FStream::BOM_UTF32BE
};
static unsigned char expected_bom_data[num_test_files][5] = {
{ 0 },
{ 0 },
{ 3, 0xEF, 0xBB, 0xBF },
{ 2, 0xFF, 0xFE },
{ 2, 0xFE, 0xFF },
{ 4, 0xFF, 0xFE, 0x00, 0x00 },
{ 4, 0x00, 0x00, 0xFE, 0xFF },
};
static unsigned char file_data[num_test_files][max_test_file_size] = {
{ 1, 'H' },
{ 11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' },
{ 11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' },
{ 22, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20,
0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00 },
{ 22, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00,
0x20, 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64 },
{ 44, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00,
0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00,
0x00, 0x6C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00 },
{ 44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00,
0x6C, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00,
0x72, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64 },
};
static int testBOM()
{
// test various encodings in binary mode
for (int i = 0; i < num_test_files; i++) {
{
kwsys::ofstream out("bom.txt", kwsys::ofstream::binary);
out.write(reinterpret_cast<const char*>(expected_bom_data[i] + 1),
*expected_bom_data[i]);
out.write(reinterpret_cast<const char*>(file_data[i] + 1),
file_data[i][0]);
}
kwsys::ifstream in("bom.txt", kwsys::ofstream::binary);
kwsys::FStream::BOM bom = kwsys::FStream::ReadBOM(in);
if (bom != expected_bom[i]) {
std::cout << "Unexpected BOM " << i << std::endl;
return 1;
}
char data[max_test_file_size];
in.read(data, file_data[i][0]);
if (!in.good()) {
std::cout << "Unable to read data " << i << std::endl;
return 1;
}
if (memcmp(data, file_data[i] + 1, file_data[i][0]) != 0) {
std::cout << "Incorrect read data " << i << std::endl;
return 1;
}
}
return 0;
}
int testFStream(int, char* [])
{
int ret = 0;
ret |= testNoFile();
ret |= testBOM();
return ret;
}
-24
View File
@@ -1,24 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int testFail(int argc, char* argv[])
{
char* env = getenv("DASHBOARD_TEST_FROM_CTEST");
int oldCtest = 0;
if (env) {
if (strcmp(env, "1") == 0) {
oldCtest = 1;
}
printf("DASHBOARD_TEST_FROM_CTEST = %s\n", env);
}
printf("%s: This test intentionally fails\n", argv[0]);
if (oldCtest) {
printf("The version of ctest is not able to handle intentionally failing "
"tests, so pass.\n");
return 0;
}
return argc;
}

Some files were not shown because too many files have changed in this diff Show More