mirror of
https://github.com/HDFGroup/hdf5.git
synced 2026-09-25 04:09:44 +03:00
Changes to isolate API Test option files and use fetchcontent (#2880)
This commit is contained in:
@@ -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
|
||||
########################
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
...
|
||||
@@ -1,2 +0,0 @@
|
||||
[hooks "chain"]
|
||||
pre-commit = GitSetup/pre-commit
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 +0,0 @@
|
||||
MESSAGE("*** This message is generated by message inside a file that is included in DartTestfile.txt ***")
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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/).
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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, ¤t_timespec);
|
||||
|
||||
current_native.tv_sec = current_timespec.tv_sec;
|
||||
current_native.tv_usec = current_timespec.tv_nsec / 1000;
|
||||
#else
|
||||
gettimeofday(¤t_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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 = ®dummy;
|
||||
|
||||
/*
|
||||
* 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}
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user