From 6768e90ef8a7ad0206d0000a297894a473d92515 Mon Sep 17 00:00:00 2001 From: Google Test Upstream Date: Tue, 27 Oct 2020 10:17:25 -0400 Subject: [PATCH 01/17] GoogleTest 2020-10-27 (3005672d) Code extracted from: https://github.com/google/googletest.git at commit 3005672db1d05f2378f642b61faa96f85498befe (master). Upstream Shortlog ----------------- Abseil Team (35): 356f2d26 Googletest export b9a8afcf Googletest export 9aaaaf3f Googletest export 70b90929 Googletest export 18a9aeda Googletest export 68ca04c2 Googletest export 48ec6409 Googletest export 5a5caab3 Googletest export d0de618a Googletest export 3d93f880 Googletest export 10ade847 Googletest export fc1e7788 Googletest export ec9be15b Googletest export df6b7594 Googletest export af1e75ce Googletest export 7b1cf6dd Googletest export a4ab0abb Googletest export bb272534 Googletest export 7aca8442 Googletest export b5687db5 Googletest export df94fc5f Googletest export fe4d5f10 Googletest export 705b9c1a Googletest export 2ff8d94d Googletest export 1fb1bb23 Googletest export 72512aa8 Googletest export 0555b0ea Googletest export d11c7617 Googletest export d4df326d Googletest export b2cb220e Googletest export 8ccc5ec5 Googletest export a4621888 Googletest export 252ee42d Googletest export 620659ed Googletest export 1845b85a Googletest export Aralox (1): ee66065b Issue 2135: Change template args in NiceMock, NaggyMock and StrictMock from A1, A2, ... to TArg1, TArg2,... to avoid clash with legacy header files Arthur Sonzogni (1): fe0ee53f Fix typo "definedin in" => "defined in" Ashik Paul (1): c4a5ee3a Fixed some minor typos Eli Lindsey (1): a2533417 fix compilation on OpenBSD 6.7 Francisco Geiman Thiesen (1): 7b2f00d9 Removing tiny-dnn from "Who is using.." Igor Nazarenko (1): 4c9ad191 Detect proto messages based on presense of DebugString. JethroSama (1): 4181d7a1 Update README.md, added missing 'a' Jun Jie (1): 5c0ef1cb Fix test failing when simple regex is used Mark Jan van Kampen (1): 44517f98 Fixes extensions missing for QNX Olivier Ldff (1): 131878ce use target_compile_features to use c++11 if cmake > 3.8 Peter Newman (1): 870a6b55 Fix a typo Rob Earhart (1): 025e1a48 Export LICENSE Ruslan Manaev (1): 113ca75c Improve FilePath::Normalize method Ting-Wei Lan (1): 2e8ebe69 Avoid using environ on FreeBSD Vladimir Goncharov (11): 0d2830b2 Make EXPECT_THROW and EXPECT_NO_THROW macros more informative 9ac4cd0f Add matchers for testing exception properties 46734d9a Small improvements: code style and property name 49d1201a Add missing documentation piece 69c510fb Add a test for duplicate catch clauses in throw matchers, fix a couple of nitpicks. 92d0a6f7 Add a test to ensure that the `Throws` matcher only invokes its argument once. 0a80845e Fix build under msvc c46bdea4 Update tests after changing an error message 4ebbfea6 Fix build under msvc a899cecb Cleanup a bulky expression, document implementation details 7f1c8bb4 Remove ThrowsMessageHasSubstr and fix some nits after review dmauro (9): 6c655699 Googletest export 5f8fcf4a Googletest export 477998ee Googletest export b55f834c Googletest export fb239f0e Googletest export 79dc0f23 Googletest export 7e7e9442 Googletest export f3dbe3ec Googletest export 3c95bf55 Googletest export jasjuang (1): 7bde252c fix clang tidy modernize-use-equals-default warnings keshavgbpecdelhi (1): 1f3484a2 Update cook_book.md krzysio (1): adeef192 Googletest export ofats (4): 08b78779 Googletest export eb660507 Googletest export c6430992 Googletest export 2cf1f99b Googletest export ranodeepbanerjee (1): ed17c8cc A slight Gramatical change. srz_zumix (3): 317ec2f2 fix GTEST_REMOVE_LEGACY_TEST_CASEAPI_ typo 7d470772 fix tests b612003c fix endif comment tbarbier (1): 4679637f Fix warning maybe-uninitialized xerus2000 (1): 296c9d29 Add timestamp to in old method mock macro guide --- BUILD.bazel | 2 + CMakeLists.txt | 2 +- README.md | 14 +- WORKSPACE | 29 +- appveyor.yml | 2 +- googlemock/CMakeLists.txt | 1 - googlemock/docs/cheat_sheet.md | 19 +- googlemock/docs/cook_book.md | 88 +- googlemock/docs/for_dummies.md | 4 +- googlemock/docs/gmock_faq.md | 2 + googlemock/docs/pump_manual.md | 4 +- googlemock/include/gmock/gmock-actions.h | 229 ++- .../include/gmock/gmock-function-mocker.h | 4 +- .../include/gmock/gmock-generated-actions.h | 82 +- .../gmock/gmock-generated-actions.h.pump | 34 +- googlemock/include/gmock/gmock-matchers.h | 382 +++++ googlemock/include/gmock/gmock-more-actions.h | 162 -- googlemock/include/gmock/gmock-nice-strict.h | 18 +- googlemock/include/gmock/gmock.h | 1 - googlemock/scripts/fuse_gmock_files.py | 129 +- googlemock/src/gmock-spec-builders.cc | 60 +- googlemock/src/gmock.cc | 2 +- .../test/gmock-generated-actions_test.cc | 27 + .../test/gmock-generated-matchers_test.cc | 1321 --------------- googlemock/test/gmock-matchers_test.cc | 1492 +++++++++++++++++ googlemock/test/gmock-more-actions_test.cc | 35 +- googlemock/test/gmock_all_test.cc | 1 - googlemock/test/gmock_output_test_golden.txt | 2 +- googletest/cmake/internal_utils.cmake | 4 + googletest/docs/advanced.md | 148 +- googletest/docs/faq.md | 16 +- googletest/docs/pkgconfig.md | 2 + googletest/docs/primer.md | 2 + googletest/include/gtest/gtest-printers.h | 57 +- googletest/include/gtest/gtest.h | 3 +- .../include/gtest/internal/gtest-internal.h | 242 ++- .../include/gtest/internal/gtest-param-util.h | 11 +- .../include/gtest/internal/gtest-string.h | 3 + googletest/src/gtest-death-test.cc | 36 +- googletest/src/gtest-filepath.cc | 12 +- googletest/src/gtest-port.cc | 7 +- googletest/src/gtest.cc | 108 +- googletest/test/googletest-death-test-test.cc | 24 + .../googletest-output-test-golden-lin.txt | 2 +- googletest/test/googletest-port-test.cc | 10 + googletest/test/googletest-printers-test.cc | 37 + googletest/test/googletest-shuffle-test_.cc | 2 +- googletest/test/gtest-typed-test_test.cc | 8 +- googletest/test/gtest_unittest.cc | 346 +++- googletest/test/gtest_xml_test_utils.py | 2 +- 50 files changed, 3172 insertions(+), 2058 deletions(-) delete mode 100644 googlemock/include/gmock/gmock-more-actions.h delete mode 100644 googlemock/test/gmock-generated-matchers_test.cc diff --git a/BUILD.bazel b/BUILD.bazel index 7e227aa00e..8099642a85 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -36,6 +36,8 @@ package(default_visibility = ["//visibility:public"]) licenses(["notice"]) +exports_files(["LICENSE"]) + config_setting( name = "windows", constraint_values = ["@bazel_tools//platforms:windows"], diff --git a/CMakeLists.txt b/CMakeLists.txt index 37e7b61211..e516b4b7a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ project(googletest-distribution) set(GOOGLETEST_VERSION 1.10.0) if (CMAKE_VERSION VERSION_GREATER "3.0.2") - if(NOT CYGWIN AND NOT MSYS) + if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX) set(CMAKE_CXX_EXTENSIONS OFF) endif() endif() diff --git a/README.md b/README.md index 1727866297..4ecfd4441f 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,6 @@ This repository is a merger of the formerly separate GoogleTest and GoogleMock projects. These were so closely related that it makes sense to maintain and release them together. -Please subscribe to the mailing list at googletestframework@googlegroups.com for -questions, discussions, and development. - ### Getting started: The information for **Google Test** is available in the @@ -76,8 +73,6 @@ following notable projects: * [Protocol Buffers](https://github.com/google/protobuf), Google's data interchange format. * The [OpenCV](http://opencv.org/) computer vision library. -* [tiny-dnn](https://github.com/tiny-dnn/tiny-dnn): header only, - dependency-free deep learning framework in C++11. ## Related Open Source Projects @@ -85,7 +80,7 @@ following notable projects: automated test-runner and Graphical User Interface with powerful features for Windows and Linux platforms. -[Google Test UI](https://github.com/ospector/gtest-gbar) is test runner that +[Google Test UI](https://github.com/ospector/gtest-gbar) is a test runner that runs your test binary, allows you to track its progress via a progress bar, and displays a list of test failures. Clicking on one shows failure text. Google Test UI is written in C#. @@ -113,8 +108,9 @@ that generates stub code for Google Test. Google Test is designed to have fairly minimal requirements to build and use with your projects, but there are some. If you notice any problems on your -platform, please notify -[googletestframework@googlegroups.com](https://groups.google.com/forum/#!forum/googletestframework). +platform, please file an issue on the +[GoogleTest GitHub Issue Tracker](https://github.com/google/googletest/issues). + Patches for fixing them are welcome! ### Build Requirements @@ -126,7 +122,7 @@ package: the build system that googletest is using internally and tests against. CMake is community-supported. -* a C++11-standard-compliant compiler +* A C++11-standard-compliant compiler ## Contributing change diff --git a/WORKSPACE b/WORKSPACE index 2289bdb7e8..1f05d21a0d 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -2,22 +2,29 @@ workspace(name = "com_google_googletest") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -# Abseil http_archive( - name = "com_google_absl", - urls = ["https://github.com/abseil/abseil-cpp/archive/master.zip"], - strip_prefix = "abseil-cpp-master", + name = "com_google_absl", # 2020-10-13T16:49:13Z + urls = [ + "https://github.com/abseil/abseil-cpp/archive/f3f785ab59478dd0312bf1b5df65d380650bf0dc.zip" + ], + strip_prefix = "abseil-cpp-f3f785ab59478dd0312bf1b5df65d380650bf0dc", + sha256 = "00c3707bf9cd5eabd1ec6932cc65b97378c043f22573be3adf7d11bb7af17d06", ) http_archive( - name = "rules_cc", - strip_prefix = "rules_cc-master", - urls = ["https://github.com/bazelbuild/rules_cc/archive/master.zip"], + name = "rules_cc", # 2020-10-05T06:01:24Z + urls = [ + "https://github.com/bazelbuild/rules_cc/archive/f055da4ff0cb2b3c73de1fe2f094ebdfb8b3acb9.zip" + ], + strip_prefix = "rules_cc-f055da4ff0cb2b3c73de1fe2f094ebdfb8b3acb9", + sha256 = "35ea62c63cd71d4000efe85f9f4f17e8afb23896c37ee9510952db2e9d8fbb70", ) http_archive( - name = "rules_python", - strip_prefix = "rules_python-master", - urls = ["https://github.com/bazelbuild/rules_python/archive/master.zip"], + name = "rules_python", # 2020-09-30T13:50:21Z + urls = [ + "https://github.com/bazelbuild/rules_python/archive/c064f7008a30f307ea7516cf52358a653011f82b.zip", + ], + strip_prefix = "rules_python-c064f7008a30f307ea7516cf52358a653011f82b", + sha256 = "6e49996ad3cf45b2232b8f94ca1e3ead369c28394c51632be8d85fe826383012", ) - diff --git a/appveyor.yml b/appveyor.yml index ec155a76ad..5c419c32f9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -60,7 +60,7 @@ install: # install Bazel if ($env:build_system -eq "bazel") { - appveyor DownloadFile https://github.com/bazelbuild/bazel/releases/download/0.28.1/bazel-0.28.1-windows-x86_64.exe -FileName bazel.exe + appveyor DownloadFile https://github.com/bazelbuild/bazel/releases/download/3.6.0/bazel-3.6.0-windows-x86_64.exe -FileName bazel.exe } if ($env:build_system -eq "cmake") { diff --git a/googlemock/CMakeLists.txt b/googlemock/CMakeLists.txt index 079c8c9639..188794270e 100644 --- a/googlemock/CMakeLists.txt +++ b/googlemock/CMakeLists.txt @@ -168,7 +168,6 @@ $env:Path = \"$project_bin;$env:Path\" cxx_test(gmock_ex_test gmock_main) cxx_test(gmock-function-mocker_test gmock_main) cxx_test(gmock-generated-actions_test gmock_main) - cxx_test(gmock-generated-matchers_test gmock_main) cxx_test(gmock-internal-utils_test gmock_main) cxx_test(gmock-matchers_test gmock_main) cxx_test(gmock-more-actions_test gmock_main) diff --git a/googlemock/docs/cheat_sheet.md b/googlemock/docs/cheat_sheet.md index a39c6e9f94..e6cffd0cfa 100644 --- a/googlemock/docs/cheat_sheet.md +++ b/googlemock/docs/cheat_sheet.md @@ -2,6 +2,8 @@ + + ## Defining a Mock Class @@ -279,9 +281,10 @@ Matcher | Description Except `Ref()`, these matchers make a *copy* of `value` in case it's modified or destructed later. If the compiler complains that `value` doesn't have a public -copy constructor, try wrap it in `ByRef()`, e.g. -`Eq(ByRef(non_copyable_value))`. If you do that, make sure `non_copyable_value` -is not changed afterwards, or the meaning of your matcher will be changed. +copy constructor, try wrap it in `std::ref()`, e.g. +`Eq(std::ref(non_copyable_value))`. If you do that, make sure +`non_copyable_value` is not changed afterwards, or the meaning of your matcher +will be changed. `IsTrue` and `IsFalse` are useful when you need to use a matcher, or for types that can be explicitly converted to Boolean, but are not implicitly converted to @@ -400,6 +403,7 @@ messages, you can use: | `Field(&class::field, m)` | `argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. | | `Key(e)` | `argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`. | | `Pair(m1, m2)` | `argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | +| `FieldsAre(m...)` | `argument` is a compatible object where each field matches piecewise with `m...`. A compatible object is any that supports the `std::tuple_size`+`get(obj)` protocol. In C++17 and up this also supports types compatible with structured bindings, like aggregates. | | `Property(&class::property, m)` | `argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. | @@ -495,7 +499,7 @@ which must be a permanent callback. | :----------------------------------- | :------------------------------------ | | `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | | `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a matcher `IsDivisibleBy(n)` to match a number divisible by `n`. | -| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | +| `MATCHER_P2(IsBetween, a, b, absl::StrCat(negation ? "isn't" : "is", " between ", PrintToString(a), " and ", PrintToString(b))) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | **Notes:** @@ -586,13 +590,12 @@ callback type instead of a derived one, e.g. ``` In `InvokeArgument(...)`, if an argument needs to be passed by reference, -wrap it inside `ByRef()`. For example, +wrap it inside `std::ref()`. For example, ```cpp -using ::testing::ByRef; using ::testing::InvokeArgument; ... -InvokeArgument<2>(5, string("Hi"), ByRef(foo)) +InvokeArgument<2>(5, string("Hi"), std::ref(foo)) ``` calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by @@ -616,7 +619,7 @@ composite action - trying to do so will result in a run-time error. | | | | :----------------------------- | :------------------------------------------ | -| `DoAll(a1, a2, ..., an)` | Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | +| `DoAll(a1, a2, ..., an)` | Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void and will receive a readonly view of the arguments. | | `IgnoreResult(a)` | Perform action `a` and ignore its result. `a` must not return void. | | `WithArg(a)` | Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | | `WithArgs(a)` | Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | diff --git a/googlemock/docs/cook_book.md b/googlemock/docs/cook_book.md index 9550d91223..817d5cabec 100644 --- a/googlemock/docs/cook_book.md +++ b/googlemock/docs/cook_book.md @@ -3,13 +3,15 @@ You can find recipes for using gMock here. If you haven't yet, please read -[this](for_dummies.md) first to make sure you understand the basics. +[the dummy guide](for_dummies.md) first to make sure you understand the basics. **Note:** gMock lives in the `testing` name space. For readability, it is recommended to write `using ::testing::Foo;` once in your file before using the name `Foo` defined by gMock. We omit such `using` statements in this section for brevity, but you should do it in your own code. + + ## Creating Mock Classes Mock classes are defined as normal classes, using the `MOCK_METHOD` macro to @@ -281,9 +283,11 @@ recipe for [mocking non-virtual methods](#MockingNonVirtualMethods). ### Old-Style `MOCK_METHODn` Macros -Before the generic `MOCK_METHOD` macro was introduced, mocks where created using -a family of macros collectively called `MOCK_METHODn`. These macros are still -supported, though migration to the new `MOCK_METHOD` is recommended. +Before the generic `MOCK_METHOD` macro +[was introduced in 2018](https://github.com/google/googletest/commit/c5f08bf91944ce1b19bcf414fa1760e69d20afc2), +mocks where created using a family of macros collectively called `MOCK_METHODn`. +These macros are still supported, though migration to the new `MOCK_METHOD` is +recommended. The macros in the `MOCK_METHODn` family differ from `MOCK_METHOD`: @@ -777,28 +781,12 @@ perhaps your test doesn't need to mock `Concrete()` at all (but it would be oh-so painful to have to define a new mock class whenever you don't need to mock one of its methods). -The trick is to leave a back door in your mock class for accessing the real -methods in the base class: - -```cpp -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD(void, Pure, (int n), (override)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD(int, Concrete, (const char* str), (override)); - - // Use this to call Concrete() defined in Foo. - int FooConcrete(const char* str) { return Foo::Concrete(str); } -}; -``` - -Now, you can call `Foo::Concrete()` inside an action by: +You can call `Foo::Concrete()` inside an action by: ```cpp ... EXPECT_CALL(foo, Concrete).WillOnce([&foo](const char* str) { - return foo.FooConcrete(str); + return foo.Foo::Concrete(str); }); ``` @@ -807,7 +795,7 @@ or tell the mock object that you don't want to mock `Concrete()`: ```cpp ... ON_CALL(foo, Concrete).WillByDefault([&foo](const char* str) { - return foo.FooConcrete(str); + return foo.Foo::Concrete(str); }); ``` @@ -871,6 +859,22 @@ using ::testing::Not; NULL)); ``` +Matchers are function objects, and parametrized matchers can be composed just +like any other function. However because their types can be long and rarely +provide meaningful information, it can be easier to express them with C++14 +generic lambdas to avoid specifying types. For example, + +```cpp +using ::testing::Contains; +using ::testing::Property; + +inline constexpr auto HasFoo = [](const auto& f) { + return Property(&MyClass::foo, Contains(f)); +}; +... + EXPECT_THAT(x, HasFoo("blah")); +``` + ### Casting Matchers {#SafeMatcherCast} gMock matchers are statically typed, meaning that the compiler can catch your @@ -1144,10 +1148,11 @@ Hamcrest project, which adds `assertThat()` to JUnit. ### Using Predicates as Matchers -gMock provides a [built-in set](#MatcherList) of matchers. In case you find them -lacking, you can use an arbitrary unary predicate function or functor as a -matcher - as long as the predicate accepts a value of the type you want. You do -this by wrapping the predicate inside the `Truly()` function, for example: +gMock provides a [built-in set](cheat_sheet.md#MatcherList) of matchers. In case +you find them lacking, you can use an arbitrary unary predicate function or +functor as a matcher - as long as the predicate accepts a value of the type you +want. You do this by wrapping the predicate inside the `Truly()` function, for +example: ```cpp using ::testing::Truly; @@ -1180,15 +1185,14 @@ executed. Just tell gMock that it should save a reference to `bar`, instead of a copy of it. Here's how: ```cpp -using ::testing::ByRef; using ::testing::Eq; using ::testing::Lt; ... // Expects that Foo()'s argument == bar. - EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); + EXPECT_CALL(mock_obj, Foo(Eq(std::ref(bar)))); // Expects that Foo()'s argument < bar. - EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); + EXPECT_CALL(mock_obj, Foo(Lt(std::ref(bar)))); ``` Remember: if you do this, don't change `bar` after the `EXPECT_CALL()`, or the @@ -1851,10 +1855,9 @@ Methods"). However, gMock doesn't let you use `ReturnRef()` in a mock function whose return type is not a reference, as doing that usually indicates a user error. So, what shall you do? -Though you may be tempted, DO NOT use `ByRef()`: +Though you may be tempted, DO NOT use `std::ref()`: ```cpp -using testing::ByRef; using testing::Return; class MockFoo : public Foo { @@ -1865,7 +1868,7 @@ class MockFoo : public Foo { int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(Return(ByRef(x))); // Wrong! + .WillRepeatedly(Return(std::ref(x))); // Wrong! x = 42; EXPECT_EQ(42, foo.GetValue()); ``` @@ -1881,9 +1884,9 @@ Expected: 42 The reason is that `Return(*value*)` converts `value` to the actual return type of the mock function at the time when the action is *created*, not when it is *executed*. (This behavior was chosen for the action to be safe when `value` is -a proxy object that references some temporary objects.) As a result, `ByRef(x)` -is converted to an `int` value (instead of a `const int&`) when the expectation -is set, and `Return(ByRef(x))` will always return 0. +a proxy object that references some temporary objects.) As a result, +`std::ref(x)` is converted to an `int` value (instead of a `const int&`) when +the expectation is set, and `Return(std::ref(x))` will always return 0. `ReturnPointee(pointer)` was provided to solve this problem specifically. It returns the value pointed to by `pointer` at the time the action is *executed*: @@ -2128,7 +2131,7 @@ class MockFoo : public Foo { DefaultValue::Clear(); ``` -Please note that changing the default value for a type can make you tests hard +Please note that changing the default value for a type can make your tests hard to understand. We recommend you to use this feature judiciously. For example, you may want to make sure the `Set()` and `Clear()` calls are right next to the code that uses your mock. @@ -2376,7 +2379,7 @@ using ::testing::InvokeArgument; ``` What if the callable takes an argument by reference? No problem - just wrap it -inside `ByRef()`: +inside `std::ref()`: ```cpp ... @@ -2385,20 +2388,19 @@ inside `ByRef()`: (override)); ... using ::testing::_; - using ::testing::ByRef; using ::testing::InvokeArgument; ... MockFoo foo; Helper helper; ... EXPECT_CALL(foo, Bar(_)) - .WillOnce(InvokeArgument<0>(5, ByRef(helper))); - // ByRef(helper) guarantees that a reference to helper, not a copy of it, - // will be passed to the callback. + .WillOnce(InvokeArgument<0>(5, std::ref(helper))); + // std::ref(helper) guarantees that a reference to helper, not a copy of + // it, will be passed to the callback. ``` What if the callable takes an argument by reference and we do **not** wrap the -argument in `ByRef()`? Then `InvokeArgument()` will *make a copy* of the +argument in `std::ref()`? Then `InvokeArgument()` will *make a copy* of the argument, and pass a *reference to the copy*, instead of a reference to the original value, to the callable. This is especially handy when the argument is a temporary value: diff --git a/googlemock/docs/for_dummies.md b/googlemock/docs/for_dummies.md index 4ce7b948db..8ba164f9a1 100644 --- a/googlemock/docs/for_dummies.md +++ b/googlemock/docs/for_dummies.md @@ -2,6 +2,8 @@ + + ## What Is gMock? When you write a prototype or test, often it's not feasible or wise to rely on @@ -106,7 +108,7 @@ the API in an interface (say, `Turtle`) and code to that interface: ```cpp class Turtle { ... - virtual ~Turtle() {}; + virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; diff --git a/googlemock/docs/gmock_faq.md b/googlemock/docs/gmock_faq.md index 7f8c647afa..14acae5302 100644 --- a/googlemock/docs/gmock_faq.md +++ b/googlemock/docs/gmock_faq.md @@ -2,6 +2,8 @@ + + ### When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? In order for a method to be mocked, it must be *virtual*, unless you use the diff --git a/googlemock/docs/pump_manual.md b/googlemock/docs/pump_manual.md index cdf7c57da2..17fb370dee 100644 --- a/googlemock/docs/pump_manual.md +++ b/googlemock/docs/pump_manual.md @@ -1,5 +1,7 @@ Pump is Useful for Meta Programming. + + # The Problem Template and macro libraries often need to define many classes, functions, or @@ -117,7 +119,7 @@ Func(a1 + a2 + a3); // If n is 3. We support the following meta programming constructs: | `$var id = exp` | Defines a named constant value. `$id` is | -: : valid util the end of the current meta : +: : valid until the end of the current meta : : : lexical block. : | :------------------------------- | :--------------------------------------- | | `$range id exp..exp` | Sets the range of an iteration variable, | diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index ecf47c4048..02b17c7d9d 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -449,6 +449,9 @@ class Action { } }; + template + using IsCompatibleFunctor = std::is_constructible, G>; + public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; @@ -460,15 +463,13 @@ class Action { // Construct an Action from a specified callable. // This cannot take std::function directly, because then Action would not be // directly constructible from lambda (it would require two conversions). - template , G>, - typename IsNoArgsFunctor = - ::std::is_constructible<::std::function, G>, - typename = typename ::std::enable_if::value>::type> + template < + typename G, + typename = typename std::enable_if, std::is_constructible, + G>>::value>::type> Action(G&& fun) { // NOLINT - Init(::std::forward(fun), IsCompatibleFunctor()); + Init(::std::forward(fun), IsCompatibleFunctor()); } // Constructs an Action from its implementation. @@ -1032,9 +1033,13 @@ struct WithArgsAction { template struct DoAllAction { private: - template - std::vector> Convert(IndexSequence) const { - return {std::get(actions)...}; + template + using NonFinalType = + typename std::conditional::value, T, const T&>::type; + + template + std::vector Convert(IndexSequence) const { + return {ActionT(std::get(actions))...}; } public: @@ -1043,21 +1048,121 @@ struct DoAllAction { template operator Action() const { // NOLINT struct Op { - std::vector> converted; + std::vector...)>> converted; Action last; R operator()(Args... args) const { auto tuple_args = std::forward_as_tuple(std::forward(args)...); for (auto& a : converted) { a.Perform(tuple_args); } - return last.Perform(tuple_args); + return last.Perform(std::move(tuple_args)); } }; - return Op{Convert(MakeIndexSequence()), + return Op{Convert...)>>( + MakeIndexSequence()), std::get(actions)}; } }; +template +struct ReturnNewAction { + T* operator()() const { + return internal::Apply( + [](const Params&... unpacked_params) { + return new T(unpacked_params...); + }, + params); + } + std::tuple params; +}; + +template +struct ReturnArgAction { + template + auto operator()(const Args&... args) const -> + typename std::tuple_element>::type { + return std::get(std::tie(args...)); + } +}; + +template +struct SaveArgAction { + Ptr pointer; + + template + void operator()(const Args&... args) const { + *pointer = std::get(std::tie(args...)); + } +}; + +template +struct SaveArgPointeeAction { + Ptr pointer; + + template + void operator()(const Args&... args) const { + *pointer = *std::get(std::tie(args...)); + } +}; + +template +struct SetArgRefereeAction { + T value; + + template + void operator()(Args&&... args) const { + using argk_type = + typename ::std::tuple_element>::type; + static_assert(std::is_lvalue_reference::value, + "Argument must be a reference type."); + std::get(std::tie(args...)) = value; + } +}; + +template +struct SetArrayArgumentAction { + I1 first; + I2 last; + + template + void operator()(const Args&... args) const { + auto value = std::get(std::tie(args...)); + for (auto it = first; it != last; ++it, (void)++value) { + *value = *it; + } + } +}; + +template +struct DeleteArgAction { + template + void operator()(const Args&... args) const { + delete std::get(std::tie(args...)); + } +}; + +template +struct ReturnPointeeAction { + Ptr pointer; + template + auto operator()(const Args&...) const -> decltype(*pointer) { + return *pointer; + } +}; + +#if GTEST_HAS_EXCEPTIONS +template +struct ThrowAction { + T exception; + // We use a conversion operator to adapt to any return type. + template + operator Action() const { // NOLINT + T copy = exception; + return [copy](Args...) -> R { throw copy; }; + } +}; +#endif // GTEST_HAS_EXCEPTIONS + } // namespace internal // An Unused object can be implicitly constructed from ANY value. @@ -1093,7 +1198,8 @@ struct DoAllAction { typedef internal::IgnoredValue Unused; // Creates an action that does actions a1, a2, ..., sequentially in -// each invocation. +// each invocation. All but the last action will have a readonly view of the +// arguments. template internal::DoAllAction::type...> DoAll( Action&&... action) { @@ -1286,22 +1392,6 @@ inline ::std::reference_wrapper ByRef(T& l_value) { // NOLINT return ::std::reference_wrapper(l_value); } -namespace internal { - -template -struct ReturnNewAction { - T* operator()() const { - return internal::Apply( - [](const Params&... unpacked_params) { - return new T(unpacked_params...); - }, - params); - } - std::tuple params; -}; - -} // namespace internal - // The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new // instance of type T, constructed on the heap with constructor arguments // a1, a2, ..., and a_k. The caller assumes ownership of the returned value. @@ -1311,6 +1401,67 @@ internal::ReturnNewAction::type...> ReturnNew( return {std::forward_as_tuple(std::forward(params)...)}; } +// Action ReturnArg() returns the k-th argument of the mock function. +template +internal::ReturnArgAction ReturnArg() { + return {}; +} + +// Action SaveArg(pointer) saves the k-th (0-based) argument of the +// mock function to *pointer. +template +internal::SaveArgAction SaveArg(Ptr pointer) { + return {pointer}; +} + +// Action SaveArgPointee(pointer) saves the value pointed to +// by the k-th (0-based) argument of the mock function to *pointer. +template +internal::SaveArgPointeeAction SaveArgPointee(Ptr pointer) { + return {pointer}; +} + +// Action SetArgReferee(value) assigns 'value' to the variable +// referenced by the k-th (0-based) argument of the mock function. +template +internal::SetArgRefereeAction::type> SetArgReferee( + T&& value) { + return {std::forward(value)}; +} + +// Action SetArrayArgument(first, last) copies the elements in +// source range [first, last) to the array pointed to by the k-th +// (0-based) argument, which can be either a pointer or an +// iterator. The action does not take ownership of the elements in the +// source range. +template +internal::SetArrayArgumentAction SetArrayArgument(I1 first, + I2 last) { + return {first, last}; +} + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +template +internal::DeleteArgAction DeleteArg() { + return {}; +} + +// This action returns the value pointed to by 'pointer'. +template +internal::ReturnPointeeAction ReturnPointee(Ptr pointer) { + return {pointer}; +} + +// Action Throw(exception) can be used in a mock function of any type +// to throw the given exception. Any copyable value can be thrown. +#if GTEST_HAS_EXCEPTIONS +template +internal::ThrowAction::type> Throw(T&& exception) { + return {std::forward(exception)}; +} +#endif // GTEST_HAS_EXCEPTIONS + namespace internal { // A macro from the ACTION* family (defined later in gmock-generated-actions.h) @@ -1388,23 +1539,15 @@ class ActionImpl> { std::tuple params_; }; -namespace invoke_argument { - -// Appears in InvokeArgumentAdl's argument list to help avoid -// accidental calls to user functions of the same name. -struct AdlTag {}; - -// InvokeArgumentAdl - a helper for InvokeArgument. +// internal::InvokeArgument - a helper for InvokeArgument action. // The basic overloads are provided here for generic functors. // Overloads for other custom-callables are provided in the // internal/custom/gmock-generated-actions.h header. template -auto InvokeArgumentAdl(AdlTag, F f, Args... args) -> decltype(f(args...)) { +auto InvokeArgument(F f, Args... args) -> decltype(f(args...)) { return f(args...); } -} // namespace invoke_argument - #define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \ , const arg##i##_type& arg##i GTEST_ATTRIBUTE_UNUSED_ #define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \ @@ -1495,6 +1638,9 @@ auto InvokeArgumentAdl(AdlTag, F f, Args... args) -> decltype(f(args...)) { \ public: \ using base_type::base_type; \ + name##Action() = default; \ + /* Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82134 */ \ + name##Action(const name##Action&) { } \ template \ class gmock_Impl : public ::testing::ActionInterface { \ public: \ @@ -1512,6 +1658,7 @@ auto InvokeArgumentAdl(AdlTag, F f, Args... args) -> decltype(f(args...)) { return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ }; \ }; \ + inline name##Action name() GTEST_MUST_USE_RESULT_; \ inline name##Action name() { return name##Action(); } \ template \ template \ diff --git a/googlemock/include/gmock/gmock-function-mocker.h b/googlemock/include/gmock/gmock-function-mocker.h index 317d6c2b7e..bfe7819a91 100644 --- a/googlemock/include/gmock/gmock-function-mocker.h +++ b/googlemock/include/gmock/gmock-function-mocker.h @@ -124,7 +124,7 @@ using internal::FunctionMocker; ::testing::tuple_size::ArgumentTuple>::value == _N, \ "This method does not take " GMOCK_PP_STRINGIZE( \ - _N) " arguments. Parenthesize all types with unproctected commas.") + _N) " arguments. Parenthesize all types with unprotected commas.") #define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec) @@ -234,7 +234,7 @@ using internal::FunctionMocker; GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I( \ GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg)) #define GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I(_arg) \ - GMOCK_PP_CAT(GMOCK_PP_IDENTITY, _arg) + GMOCK_PP_IDENTITY _arg #define GMOCK_INTERNAL_IS_CALLTYPE_HELPER_Calltype diff --git a/googlemock/include/gmock/gmock-generated-actions.h b/googlemock/include/gmock/gmock-generated-actions.h index 7030a98e99..124bd01125 100644 --- a/googlemock/include/gmock/gmock-generated-actions.h +++ b/googlemock/include/gmock/gmock-generated-actions.h @@ -47,6 +47,8 @@ #include "gmock/gmock-actions.h" #include "gmock/internal/gmock-port.h" +// Include any custom callback actions added by the local installation. +#include "gmock/internal/custom/gmock-generated-actions.h" // Sometimes you want to give an action explicit template parameters // that cannot be inferred from its value parameters. ACTION() and @@ -292,6 +294,20 @@ p7(::std::move(gmock_p7)), p8(::std::move(gmock_p8)), \ p9(::std::move(gmock_p9)) +// Defines the copy constructor +#define GMOCK_INTERNAL_DEFN_COPY_AND_0_VALUE_PARAMS() \ + {} // Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82134 +#define GMOCK_INTERNAL_DEFN_COPY_AND_1_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_2_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_3_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_4_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_5_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_6_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_7_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_8_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_9_VALUE_PARAMS(...) = default; +#define GMOCK_INTERNAL_DEFN_COPY_AND_10_VALUE_PARAMS(...) = default; + // Declares the fields for storing the value parameters. #define GMOCK_INTERNAL_DEFN_AND_0_VALUE_PARAMS() #define GMOCK_INTERNAL_DEFN_AND_1_VALUE_PARAMS(p0) p0##_type p0; @@ -420,6 +436,11 @@ public:\ explicit GMOCK_ACTION_CLASS_(name, value_params)\ GMOCK_INTERNAL_INIT_##value_params {}\ + GMOCK_ACTION_CLASS_(name, value_params)(\ + const GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params>&)\ + GMOCK_INTERNAL_DEFN_COPY_##value_params\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ @@ -442,6 +463,12 @@ }\ GMOCK_INTERNAL_DEFN_##value_params\ };\ + template \ + GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\ + GMOCK_INTERNAL_DECL_##value_params) GTEST_MUST_USE_RESULT_;\ template \ inline GMOCK_ACTION_CLASS_(name, value_params)<\ @@ -511,91 +538,71 @@ namespace testing { ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_0_VALUE_PARAMS()) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args)); + return internal::InvokeArgument(::std::get(args)); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_1_VALUE_PARAMS(p0)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0); + return internal::InvokeArgument(::std::get(args), p0); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_2_VALUE_PARAMS(p0, p1)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1); + return internal::InvokeArgument(::std::get(args), p0, p1); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_3_VALUE_PARAMS(p0, p1, p2)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1, p2); + return internal::InvokeArgument(::std::get(args), p0, p1, p2); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1, p2, p3); + return internal::InvokeArgument(::std::get(args), p0, p1, p2, p3); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1, p2, p3, p4); + return internal::InvokeArgument(::std::get(args), p0, p1, p2, p3, p4); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1, p2, p3, p4, p5); + return internal::InvokeArgument(::std::get(args), p0, p1, p2, p3, p4, p5); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1, p2, p3, p4, p5, p6); + return internal::InvokeArgument(::std::get(args), p0, p1, p2, p3, p4, p5, + p6); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1, p2, p3, p4, p5, p6, p7); + return internal::InvokeArgument(::std::get(args), p0, p1, p2, p3, p4, p5, + p6, p7); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1, p2, p3, p4, p5, p6, p7, - p8); + return internal::InvokeArgument(::std::get(args), p0, p1, p2, p3, p4, p5, + p6, p7, p8); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args), p0, p1, p2, p3, p4, p5, p6, p7, - p8, p9); + return internal::InvokeArgument(::std::get(args), p0, p1, p2, p3, p4, p5, + p6, p7, p8, p9); } #ifdef _MSC_VER @@ -604,9 +611,4 @@ ACTION_TEMPLATE(InvokeArgument, } // namespace testing -// Include any custom callback actions added by the local installation. -// We must include this header at the end to make sure it can use the -// declarations from this file. -#include "gmock/internal/custom/gmock-generated-actions.h" - #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/googlemock/include/gmock/gmock-generated-actions.h.pump b/googlemock/include/gmock/gmock-generated-actions.h.pump index 3430204f36..7a7fc9f449 100644 --- a/googlemock/include/gmock/gmock-generated-actions.h.pump +++ b/googlemock/include/gmock/gmock-generated-actions.h.pump @@ -49,10 +49,12 @@ $$}} This meta comment fixes auto-indentation in editors. #include "gmock/gmock-actions.h" #include "gmock/internal/gmock-port.h" +// Include any custom callback actions added by the local installation. +#include "gmock/internal/custom/gmock-generated-actions.h" + $range i 0..n $range k 0..n-1 - // Sometimes you want to give an action explicit template parameters // that cannot be inferred from its value parameters. ACTION() and // ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that @@ -173,6 +175,16 @@ $range j 0..i-1 ($for j, [[p$j##_type gmock_p$j]])$if i>0 [[ : ]]$for j, [[p$j(::std::move(gmock_p$j))]] +]] + +// Defines the copy constructor + +$for i [[ +#define GMOCK_INTERNAL_DEFN_COPY_AND_$i[[]]_VALUE_PARAMS$if i == 0[[() \ + {} // Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82134 +]] $else [[(...) = default;]] + + ]] // Declares the fields for storing the value parameters. @@ -238,6 +250,11 @@ $range k 0..n-1 public:\ explicit GMOCK_ACTION_CLASS_(name, value_params)\ GMOCK_INTERNAL_INIT_##value_params {}\ + GMOCK_ACTION_CLASS_(name, value_params)(\ + const GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params>&)\ + GMOCK_INTERNAL_DEFN_COPY_##value_params\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ @@ -260,6 +277,12 @@ $range k 0..n-1 }\ GMOCK_INTERNAL_DEFN_##value_params\ };\ + template \ + GMOCK_ACTION_CLASS_(name, value_params)<\ + GMOCK_INTERNAL_LIST_##template_params\ + GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\ + GMOCK_INTERNAL_DECL_##value_params) GTEST_MUST_USE_RESULT_;\ template \ inline GMOCK_ACTION_CLASS_(name, value_params)<\ @@ -333,9 +356,7 @@ $range j 0..i-1 ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl(internal::invoke_argument::AdlTag(), - ::std::get(args)$for j[[, p$j]]); + return internal::InvokeArgument(::std::get(args)$for j[[, p$j]]); } ]] @@ -346,9 +367,4 @@ ACTION_TEMPLATE(InvokeArgument, } // namespace testing -// Include any custom callback actions added by the local installation. -// We must include this header at the end to make sure it can use the -// declarations from this file. -#include "gmock/internal/custom/gmock-generated-actions.h" - #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 0bc9b3649f..13a46712a8 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -2879,6 +2879,203 @@ class PairMatcher { const SecondMatcher second_matcher_; }; +template +auto UnpackStructImpl(const T& t, IndexSequence, int) + -> decltype(std::tie(get(t)...)) { + static_assert(std::tuple_size::value == sizeof...(I), + "Number of arguments doesn't match the number of fields."); + return std::tie(get(t)...); +} + +#if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 201606 +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<1>, char) { + const auto& [a] = t; + return std::tie(a); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<2>, char) { + const auto& [a, b] = t; + return std::tie(a, b); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<3>, char) { + const auto& [a, b, c] = t; + return std::tie(a, b, c); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<4>, char) { + const auto& [a, b, c, d] = t; + return std::tie(a, b, c, d); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<5>, char) { + const auto& [a, b, c, d, e] = t; + return std::tie(a, b, c, d, e); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<6>, char) { + const auto& [a, b, c, d, e, f] = t; + return std::tie(a, b, c, d, e, f); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<7>, char) { + const auto& [a, b, c, d, e, f, g] = t; + return std::tie(a, b, c, d, e, f, g); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<8>, char) { + const auto& [a, b, c, d, e, f, g, h] = t; + return std::tie(a, b, c, d, e, f, g, h); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<9>, char) { + const auto& [a, b, c, d, e, f, g, h, i] = t; + return std::tie(a, b, c, d, e, f, g, h, i); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<10>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j] = t; + return std::tie(a, b, c, d, e, f, g, h, i, j); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<11>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k] = t; + return std::tie(a, b, c, d, e, f, g, h, i, j, k); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<12>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l] = t; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<13>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m] = t; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<14>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n] = t; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<15>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] = t; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); +} +template +auto UnpackStructImpl(const T& t, MakeIndexSequence<16>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = t; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); +} +#endif // defined(__cpp_structured_bindings) + +template +auto UnpackStruct(const T& t) + -> decltype((UnpackStructImpl)(t, MakeIndexSequence{}, 0)) { + return (UnpackStructImpl)(t, MakeIndexSequence{}, 0); +} + +// Helper function to do comma folding in C++11. +// The array ensures left-to-right order of evaluation. +// Usage: VariadicExpand({expr...}); +template +void VariadicExpand(const T (&)[N]) {} + +template +class FieldsAreMatcherImpl; + +template +class FieldsAreMatcherImpl> + : public MatcherInterface { + using UnpackedType = + decltype(UnpackStruct(std::declval())); + using MatchersType = std::tuple< + Matcher::type&>...>; + + public: + template + explicit FieldsAreMatcherImpl(const Inner& matchers) + : matchers_(testing::SafeMatcherCast< + const typename std::tuple_element::type&>( + std::get(matchers))...) {} + + void DescribeTo(::std::ostream* os) const override { + const char* separator = ""; + VariadicExpand( + {(*os << separator << "has field #" << I << " that ", + std::get(matchers_).DescribeTo(os), separator = ", and ")...}); + } + + void DescribeNegationTo(::std::ostream* os) const override { + const char* separator = ""; + VariadicExpand({(*os << separator << "has field #" << I << " that ", + std::get(matchers_).DescribeNegationTo(os), + separator = ", or ")...}); + } + + bool MatchAndExplain(Struct t, MatchResultListener* listener) const override { + return MatchInternal((UnpackStruct)(t), listener); + } + + private: + bool MatchInternal(UnpackedType tuple, MatchResultListener* listener) const { + if (!listener->IsInterested()) { + // If the listener is not interested, we don't need to construct the + // explanation. + bool good = true; + VariadicExpand({good = good && std::get(matchers_).Matches( + std::get(tuple))...}); + return good; + } + + size_t failed_pos = ~size_t{}; + + std::vector inner_listener(sizeof...(I)); + + VariadicExpand( + {failed_pos == ~size_t{} && !std::get(matchers_).MatchAndExplain( + std::get(tuple), &inner_listener[I]) + ? failed_pos = I + : 0 ...}); + if (failed_pos != ~size_t{}) { + *listener << "whose field #" << failed_pos << " does not match"; + PrintIfNotEmpty(inner_listener[failed_pos].str(), listener->stream()); + return false; + } + + *listener << "whose all elements match"; + const char* separator = ", where"; + for (size_t index = 0; index < sizeof...(I); ++index) { + const std::string str = inner_listener[index].str(); + if (!str.empty()) { + *listener << separator << " field #" << index << " is a value " << str; + separator = ", and"; + } + } + + return true; + } + + MatchersType matchers_; +}; + +template +class FieldsAreMatcher { + public: + explicit FieldsAreMatcher(Inner... inner) : matchers_(std::move(inner)...) {} + + template + operator Matcher() const { // NOLINT + return Matcher( + new FieldsAreMatcherImpl>( + matchers_)); + } + + private: + std::tuple matchers_; +}; + // Implements ElementsAre() and ElementsAreArray(). template class ElementsAreMatcherImpl : public MatcherInterface { @@ -4514,6 +4711,19 @@ Pair(FirstMatcher first_matcher, SecondMatcher second_matcher) { first_matcher, second_matcher); } +namespace no_adl { +// FieldsAre(matchers...) matches piecewise the fields of compatible structs. +// These include those that support `get(obj)`, and when structured bindings +// are enabled any class that supports them. +// In particular, `std::tuple`, `std::pair`, `std::array` and aggregate types. +template +internal::FieldsAreMatcher::type...> FieldsAre( + M&&... matchers) { + return internal::FieldsAreMatcher::type...>( + std::forward(matchers)...); +} +} // namespace no_adl + // Returns a predicate that is satisfied by anything that matches the // given matcher. template @@ -4725,6 +4935,175 @@ PolymorphicMatcher > VariantWith( internal::variant_matcher::VariantMatcher(matcher)); } +#if GTEST_HAS_EXCEPTIONS + +// Anything inside the `internal` namespace is internal to the implementation +// and must not be used in user code! +namespace internal { + +class WithWhatMatcherImpl { + public: + WithWhatMatcherImpl(Matcher matcher) + : matcher_(std::move(matcher)) {} + + void DescribeTo(std::ostream* os) const { + *os << "contains .what() that "; + matcher_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const { + *os << "contains .what() that does not "; + matcher_.DescribeTo(os); + } + + template + bool MatchAndExplain(const Err& err, MatchResultListener* listener) const { + *listener << "which contains .what() that "; + return matcher_.MatchAndExplain(err.what(), listener); + } + + private: + const Matcher matcher_; +}; + +inline PolymorphicMatcher WithWhat( + Matcher m) { + return MakePolymorphicMatcher(WithWhatMatcherImpl(std::move(m))); +} + +template +class ExceptionMatcherImpl { + class NeverThrown { + public: + const char* what() const noexcept { + return "this exception should never be thrown"; + } + }; + + // If the matchee raises an exception of a wrong type, we'd like to + // catch it and print its message and type. To do that, we add an additional + // catch clause: + // + // try { ... } + // catch (const Err&) { /* an expected exception */ } + // catch (const std::exception&) { /* exception of a wrong type */ } + // + // However, if the `Err` itself is `std::exception`, we'd end up with two + // identical `catch` clauses: + // + // try { ... } + // catch (const std::exception&) { /* an expected exception */ } + // catch (const std::exception&) { /* exception of a wrong type */ } + // + // This can cause a warning or an error in some compilers. To resolve + // the issue, we use a fake error type whenever `Err` is `std::exception`: + // + // try { ... } + // catch (const std::exception&) { /* an expected exception */ } + // catch (const NeverThrown&) { /* exception of a wrong type */ } + using DefaultExceptionType = typename std::conditional< + std::is_same::type>::type, + std::exception>::value, + const NeverThrown&, const std::exception&>::type; + + public: + ExceptionMatcherImpl(Matcher matcher) + : matcher_(std::move(matcher)) {} + + void DescribeTo(std::ostream* os) const { + *os << "throws an exception which is a " << GetTypeName(); + *os << " which "; + matcher_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const { + *os << "throws an exception which is not a " << GetTypeName(); + *os << " which "; + matcher_.DescribeNegationTo(os); + } + + template + bool MatchAndExplain(T&& x, MatchResultListener* listener) const { + try { + (void)(std::forward(x)()); + } catch (const Err& err) { + *listener << "throws an exception which is a " << GetTypeName(); + *listener << " "; + return matcher_.MatchAndExplain(err, listener); + } catch (DefaultExceptionType err) { +#if GTEST_HAS_RTTI + *listener << "throws an exception of type " << GetTypeName(typeid(err)); + *listener << " "; +#else + *listener << "throws an std::exception-derived type "; +#endif + *listener << "with description \"" << err.what() << "\""; + return false; + } catch (...) { + *listener << "throws an exception of an unknown type"; + return false; + } + + *listener << "does not throw any exception"; + return false; + } + + private: + const Matcher matcher_; +}; + +} // namespace internal + +// Throws() +// Throws(exceptionMatcher) +// ThrowsMessage(messageMatcher) +// +// This matcher accepts a callable and verifies that when invoked, it throws +// an exception with the given type and properties. +// +// Examples: +// +// EXPECT_THAT( +// []() { throw std::runtime_error("message"); }, +// Throws()); +// +// EXPECT_THAT( +// []() { throw std::runtime_error("message"); }, +// ThrowsMessage(HasSubstr("message"))); +// +// EXPECT_THAT( +// []() { throw std::runtime_error("message"); }, +// Throws( +// Property(&std::runtime_error::what, HasSubstr("message")))); + +template +PolymorphicMatcher> Throws() { + return MakePolymorphicMatcher( + internal::ExceptionMatcherImpl(A())); +} + +template +PolymorphicMatcher> Throws( + const ExceptionMatcher& exception_matcher) { + // Using matcher cast allows users to pass a matcher of a more broad type. + // For example user may want to pass Matcher + // to Throws, or Matcher to Throws. + return MakePolymorphicMatcher(internal::ExceptionMatcherImpl( + SafeMatcherCast(exception_matcher))); +} + +template +PolymorphicMatcher> ThrowsMessage( + MessageMatcher&& message_matcher) { + static_assert(std::is_base_of::value, + "expected an std::exception-derived type"); + return Throws(internal::WithWhat( + MatcherCast(std::forward(message_matcher)))); +} + +#endif // GTEST_HAS_EXCEPTIONS + // These macros allow using matchers to check values in Google Test // tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher) // succeed if and only if the value matches the matcher. If the assertion @@ -4884,6 +5263,9 @@ PolymorphicMatcher > VariantWith( #define GMOCK_INTERNAL_MATCHER_ARG_USAGE(i, data_unused, arg_unused) \ , gmock_p##i +// To prevent ADL on certain functions we put them on a separate namespace. +using namespace no_adl; // NOLINT + } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 diff --git a/googlemock/include/gmock/gmock-more-actions.h b/googlemock/include/gmock/gmock-more-actions.h deleted file mode 100644 index d42484aef2..0000000000 --- a/googlemock/include/gmock/gmock-more-actions.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2007, Google Inc. -// 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 Google Inc. nor the names of its -// 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 -// OWNER 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. - - -// Google Mock - a framework for writing C++ mock classes. -// -// This file implements some actions that depend on gmock-generated-actions.h. - -// GOOGLETEST_CM0002 DO NOT DELETE - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ - -#include -#include - -#include "gmock/gmock-generated-actions.h" - -namespace testing { -namespace internal { - -// An internal replacement for std::copy which mimics its behavior. This is -// necessary because Visual Studio deprecates ::std::copy, issuing warning 4996. -// However Visual Studio 2010 and later do not honor #pragmas which disable that -// warning. -template -inline OutputIterator CopyElements(InputIterator first, - InputIterator last, - OutputIterator output) { - for (; first != last; ++first, ++output) { - *output = *first; - } - return output; -} - -} // namespace internal - -// Various overloads for Invoke(). - -// The ACTION*() macros trigger warning C4100 (unreferenced formal -// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in -// the macro definition, as the warnings are generated when the macro -// is expanded and macro expansion cannot contain #pragma. Therefore -// we suppress them here. -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4100) -#endif - -// Action ReturnArg() returns the k-th argument of the mock function. -ACTION_TEMPLATE(ReturnArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_0_VALUE_PARAMS()) { - return ::std::get(args); -} - -// Action SaveArg(pointer) saves the k-th (0-based) argument of the -// mock function to *pointer. -ACTION_TEMPLATE(SaveArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(pointer)) { - *pointer = ::std::get(args); -} - -// Action SaveArgPointee(pointer) saves the value pointed to -// by the k-th (0-based) argument of the mock function to *pointer. -ACTION_TEMPLATE(SaveArgPointee, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(pointer)) { - *pointer = *::std::get(args); -} - -// Action SetArgReferee(value) assigns 'value' to the variable -// referenced by the k-th (0-based) argument of the mock function. -ACTION_TEMPLATE(SetArgReferee, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(value)) { - typedef typename ::std::tuple_element::type argk_type; - // Ensures that argument #k is a reference. If you get a compiler - // error on the next line, you are using SetArgReferee(value) in - // a mock function whose k-th (0-based) argument is not a reference. - GTEST_COMPILE_ASSERT_(std::is_reference::value, - SetArgReferee_must_be_used_with_a_reference_argument); - ::std::get(args) = value; -} - -// Action SetArrayArgument(first, last) copies the elements in -// source range [first, last) to the array pointed to by the k-th -// (0-based) argument, which can be either a pointer or an -// iterator. The action does not take ownership of the elements in the -// source range. -ACTION_TEMPLATE(SetArrayArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_2_VALUE_PARAMS(first, last)) { - // Visual Studio deprecates ::std::copy, so we use our own copy in that case. -#ifdef _MSC_VER - internal::CopyElements(first, last, ::std::get(args)); -#else - ::std::copy(first, last, ::std::get(args)); -#endif -} - -// Action DeleteArg() deletes the k-th (0-based) argument of the mock -// function. -ACTION_TEMPLATE(DeleteArg, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_0_VALUE_PARAMS()) { - delete ::std::get(args); -} - -// This action returns the value pointed to by 'pointer'. -ACTION_P(ReturnPointee, pointer) { return *pointer; } - -// Action Throw(exception) can be used in a mock function of any type -// to throw the given exception. Any copyable value can be thrown. -#if GTEST_HAS_EXCEPTIONS - -// Suppresses the 'unreachable code' warning that VC generates in opt modes. -# ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4702) // Temporarily disables warning 4702. -# endif -ACTION_P(Throw, exception) { throw exception; } -# ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -# endif - -#endif // GTEST_HAS_EXCEPTIONS - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -} // namespace testing - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_ diff --git a/googlemock/include/gmock/gmock-nice-strict.h b/googlemock/include/gmock/gmock-nice-strict.h index 5495a9805b..a5579afc24 100644 --- a/googlemock/include/gmock/gmock-nice-strict.h +++ b/googlemock/include/gmock/gmock-nice-strict.h @@ -89,9 +89,9 @@ class NiceMock : public MockClass { internal::ImplicitCast_(this)); } - template - NiceMock(A1&& arg1, A2&& arg2, An&&... args) - : MockClass(std::forward(arg1), std::forward(arg2), + template + NiceMock(TArg1&& arg1, TArg2&& arg2, An&&... args) + : MockClass(std::forward(arg1), std::forward(arg2), std::forward(args)...) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); @@ -127,9 +127,9 @@ class NaggyMock : public MockClass { internal::ImplicitCast_(this)); } - template - NaggyMock(A1&& arg1, A2&& arg2, An&&... args) - : MockClass(std::forward(arg1), std::forward(arg2), + template + NaggyMock(TArg1&& arg1, TArg2&& arg2, An&&... args) + : MockClass(std::forward(arg1), std::forward(arg2), std::forward(args)...) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); @@ -165,9 +165,9 @@ class StrictMock : public MockClass { internal::ImplicitCast_(this)); } - template - StrictMock(A1&& arg1, A2&& arg2, An&&... args) - : MockClass(std::forward(arg1), std::forward(arg2), + template + StrictMock(TArg1&& arg1, TArg2&& arg2, An&&... args) + : MockClass(std::forward(arg1), std::forward(arg2), std::forward(args)...) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); diff --git a/googlemock/include/gmock/gmock.h b/googlemock/include/gmock/gmock.h index 3c317b6d47..8a4aceaee1 100644 --- a/googlemock/include/gmock/gmock.h +++ b/googlemock/include/gmock/gmock.h @@ -61,7 +61,6 @@ #include "gmock/gmock-function-mocker.h" #include "gmock/gmock-generated-actions.h" #include "gmock/gmock-matchers.h" -#include "gmock/gmock-more-actions.h" #include "gmock/gmock-more-matchers.h" #include "gmock/gmock-nice-strict.h" #include "gmock/internal/gmock-internal-utils.h" diff --git a/googlemock/scripts/fuse_gmock_files.py b/googlemock/scripts/fuse_gmock_files.py index c33c7253fe..c3ba3b8337 100755 --- a/googlemock/scripts/fuse_gmock_files.py +++ b/googlemock/scripts/fuse_gmock_files.py @@ -28,8 +28,8 @@ # 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. +"""fuse_gmock_files.py v0.1.0. -"""fuse_gmock_files.py v0.1.0 Fuses Google Mock and Google Test source code into two .h files and a .cc file. SYNOPSIS @@ -55,27 +55,29 @@ This tool is experimental. In particular, it assumes that there is no conditional inclusion of Google Mock or Google Test headers. Please report any problems to googlemock@googlegroups.com. You can read -https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md for more +https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md +for more information. """ -__author__ = 'wan@google.com (Zhanyong Wan)' +from __future__ import print_function import os import re -import sets import sys +__author__ = 'wan@google.com (Zhanyong Wan)' + # We assume that this file is in the scripts/ directory in the Google # Mock root directory. DEFAULT_GMOCK_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..') # We need to call into googletest/scripts/fuse_gtest_files.py. sys.path.append(os.path.join(DEFAULT_GMOCK_ROOT_DIR, '../googletest/scripts')) -import fuse_gtest_files -gtest = fuse_gtest_files +import fuse_gtest_files as gtest # pylint:disable=g-import-not-at-top -# Regex for matching '#include "gmock/..."'. +# Regex for matching +# '#include "gmock/..."'. INCLUDE_GMOCK_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(gmock/.+)"') # Where to find the source seed files. @@ -98,6 +100,9 @@ def ValidateGMockRootDir(gmock_root): """Makes sure gmock_root points to a valid gmock root directory. The function aborts the program on failure. + + Args: + gmock_root: A string with the mock root directory. """ gtest.ValidateGTestRootDir(GetGTestRootDir(gmock_root)) @@ -109,6 +114,9 @@ def ValidateOutputDir(output_dir): """Makes sure output_dir points to a valid output directory. The function aborts the program on failure. + + Args: + output_dir: A string representing the output directory. """ gtest.VerifyOutputFile(output_dir, gtest.GTEST_H_OUTPUT) @@ -119,8 +127,8 @@ def ValidateOutputDir(output_dir): def FuseGMockH(gmock_root, output_dir): """Scans folder gmock_root to generate gmock/gmock.h in output_dir.""" - output_file = file(os.path.join(output_dir, GMOCK_H_OUTPUT), 'w') - processed_files = sets.Set() # Holds all gmock headers we've processed. + output_file = open(os.path.join(output_dir, GMOCK_H_OUTPUT), 'w') + processed_files = set() # Holds all gmock headers we've processed. def ProcessFile(gmock_header_path): """Processes the given gmock header file.""" @@ -132,25 +140,29 @@ def ProcessFile(gmock_header_path): processed_files.add(gmock_header_path) # Reads each line in the given gmock header. - for line in file(os.path.join(gmock_root, gmock_header_path), 'r'): - m = INCLUDE_GMOCK_FILE_REGEX.match(line) - if m: - # It's '#include "gmock/..."' - let's process it recursively. - ProcessFile('include/' + m.group(1)) - else: - m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line) + + with open(os.path.join(gmock_root, gmock_header_path), 'r') as fh: + for line in fh: + m = INCLUDE_GMOCK_FILE_REGEX.match(line) if m: - # It's '#include "gtest/foo.h"'. We translate it to - # "gtest/gtest.h", regardless of what foo is, since all - # gtest headers are fused into gtest/gtest.h. - - # There is no need to #include gtest.h twice. - if not gtest.GTEST_H_SEED in processed_files: - processed_files.add(gtest.GTEST_H_SEED) - output_file.write('#include "%s"\n' % (gtest.GTEST_H_OUTPUT,)) + # '#include "gmock/..."' + # - let's process it recursively. + ProcessFile('include/' + m.group(1)) else: - # Otherwise we copy the line unchanged to the output file. - output_file.write(line) + m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line) + if m: + # '#include "third_party/googletest/googletest/ + # include/gtest/foo.h"'. + # We translate it to "gtest/gtest.h", regardless of what foo is, + # since all gtest headers are fused into gtest/gtest.h. + + # There is no need to #include gtest.h twice. + if gtest.GTEST_H_SEED not in processed_files: + processed_files.add(gtest.GTEST_H_SEED) + output_file.write('#include "%s"\n' % (gtest.GTEST_H_OUTPUT,)) + else: + # Otherwise we copy the line unchanged to the output file. + output_file.write(line) ProcessFile(GMOCK_H_SEED) output_file.close() @@ -159,7 +171,7 @@ def ProcessFile(gmock_header_path): def FuseGMockAllCcToFile(gmock_root, output_file): """Scans folder gmock_root to fuse gmock-all.cc into output_file.""" - processed_files = sets.Set() + processed_files = set() def ProcessFile(gmock_source_file): """Processes the given gmock source file.""" @@ -171,32 +183,37 @@ def ProcessFile(gmock_source_file): processed_files.add(gmock_source_file) # Reads each line in the given gmock source file. - for line in file(os.path.join(gmock_root, gmock_source_file), 'r'): - m = INCLUDE_GMOCK_FILE_REGEX.match(line) - if m: - # It's '#include "gmock/foo.h"'. We treat it as '#include - # "gmock/gmock.h"', as all other gmock headers are being fused - # into gmock.h and cannot be #included directly. - - # There is no need to #include "gmock/gmock.h" more than once. - if not GMOCK_H_SEED in processed_files: - processed_files.add(GMOCK_H_SEED) - output_file.write('#include "%s"\n' % (GMOCK_H_OUTPUT,)) - else: - m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line) + + with open(os.path.join(gmock_root, gmock_source_file), 'r') as fh: + for line in fh: + m = INCLUDE_GMOCK_FILE_REGEX.match(line) if m: - # It's '#include "gtest/..."'. - # There is no need to #include gtest.h as it has been - # #included by gtest-all.cc. - pass + # '#include "gmock/foo.h"'. + # We treat it as '#include "gmock/gmock.h"', as all other gmock + # headers are being fused into gmock.h and cannot be + # included directly. No need to #include + # "third_party/googletest/googlemock/include/gmock/gmock.h" + # more than once. + + if GMOCK_H_SEED not in processed_files: + processed_files.add(GMOCK_H_SEED) + output_file.write('#include "%s"\n' % (GMOCK_H_OUTPUT,)) else: - m = gtest.INCLUDE_SRC_FILE_REGEX.match(line) + m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line) if m: - # It's '#include "src/foo"' - let's process it recursively. - ProcessFile(m.group(1)) + # '#include "gtest/..."'. + # There is no need to #include gtest.h as it has been + # #included by gtest-all.cc. + + pass else: - # Otherwise we copy the line unchanged to the output file. - output_file.write(line) + m = gtest.INCLUDE_SRC_FILE_REGEX.match(line) + if m: + # It's '#include "src/foo"' - let's process it recursively. + ProcessFile(m.group(1)) + else: + # Otherwise we copy the line unchanged to the output file. + output_file.write(line) ProcessFile(GMOCK_ALL_CC_SEED) @@ -204,12 +221,12 @@ def ProcessFile(gmock_source_file): def FuseGMockGTestAllCc(gmock_root, output_dir): """Scans folder gmock_root to generate gmock-gtest-all.cc in output_dir.""" - output_file = file(os.path.join(output_dir, GMOCK_GTEST_ALL_CC_OUTPUT), 'w') - # First, fuse gtest-all.cc into gmock-gtest-all.cc. - gtest.FuseGTestAllCcToFile(GetGTestRootDir(gmock_root), output_file) - # Next, append fused gmock-all.cc to gmock-gtest-all.cc. - FuseGMockAllCcToFile(gmock_root, output_file) - output_file.close() + with open(os.path.join(output_dir, GMOCK_GTEST_ALL_CC_OUTPUT), + 'w') as output_file: + # First, fuse gtest-all.cc into gmock-gtest-all.cc. + gtest.FuseGTestAllCcToFile(GetGTestRootDir(gmock_root), output_file) + # Next, append fused gmock-all.cc to gmock-gtest-all.cc. + FuseGMockAllCcToFile(gmock_root, output_file) def FuseGMock(gmock_root, output_dir): @@ -232,7 +249,7 @@ def main(): # fuse_gmock_files.py GMOCK_ROOT_DIR OUTPUT_DIR FuseGMock(sys.argv[1], sys.argv[2]) else: - print __doc__ + print(__doc__) sys.exit(1) diff --git a/googlemock/src/gmock-spec-builders.cc b/googlemock/src/gmock-spec-builders.cc index 81ea98949c..05a50f67c2 100644 --- a/googlemock/src/gmock-spec-builders.cc +++ b/googlemock/src/gmock-spec-builders.cc @@ -433,10 +433,10 @@ UntypedActionResultHolderBase* UntypedFunctionMockerBase::UntypedInvokeWith( // The UntypedFindMatchingExpectation() function acquires and // releases g_gmock_mutex. + const ExpectationBase* const untyped_expectation = - this->UntypedFindMatchingExpectation( - untyped_args, &untyped_action, &is_excessive, - &ss, &why); + this->UntypedFindMatchingExpectation(untyped_args, &untyped_action, + &is_excessive, &ss, &why); const bool found = untyped_expectation != nullptr; // True if and only if we need to print the call's arguments @@ -461,26 +461,42 @@ UntypedActionResultHolderBase* UntypedFunctionMockerBase::UntypedInvokeWith( untyped_expectation->DescribeLocationTo(&loc); } - UntypedActionResultHolderBase* const result = - untyped_action == nullptr - ? this->UntypedPerformDefaultAction(untyped_args, ss.str()) - : this->UntypedPerformAction(untyped_action, untyped_args); - if (result != nullptr) result->PrintAsActionResult(&ss); - ss << "\n" << why.str(); - - if (!found) { - // No expectation matches this call - reports a failure. - Expect(false, nullptr, -1, ss.str()); - } else if (is_excessive) { - // We had an upper-bound violation and the failure message is in ss. - Expect(false, untyped_expectation->file(), - untyped_expectation->line(), ss.str()); - } else { - // We had an expected call and the matching expectation is - // described in ss. - Log(kInfo, loc.str() + ss.str(), 2); + UntypedActionResultHolderBase* result = nullptr; + + auto perform_action = [&] { + return untyped_action == nullptr + ? this->UntypedPerformDefaultAction(untyped_args, ss.str()) + : this->UntypedPerformAction(untyped_action, untyped_args); + }; + auto handle_failures = [&] { + ss << "\n" << why.str(); + + if (!found) { + // No expectation matches this call - reports a failure. + Expect(false, nullptr, -1, ss.str()); + } else if (is_excessive) { + // We had an upper-bound violation and the failure message is in ss. + Expect(false, untyped_expectation->file(), untyped_expectation->line(), + ss.str()); + } else { + // We had an expected call and the matching expectation is + // described in ss. + Log(kInfo, loc.str() + ss.str(), 2); + } + }; +#if GTEST_HAS_EXCEPTIONS + try { + result = perform_action(); + } catch (...) { + handle_failures(); + throw; } +#else + result = perform_action(); +#endif + if (result != nullptr) result->PrintAsActionResult(&ss); + handle_failures(); return result; } @@ -624,7 +640,7 @@ class MockObjectRegistry { if (leaked_count > 0) { std::cout << "\nERROR: " << leaked_count << " leaked mock " << (leaked_count == 1 ? "object" : "objects") - << " found at program exit. Expectations on a mock object is " + << " found at program exit. Expectations on a mock object are " "verified when the object is destructed. Leaking a mock " "means that its expectations aren't verified, which is " "usually a test bug. If you really intend to leak a mock, " diff --git a/googlemock/src/gmock.cc b/googlemock/src/gmock.cc index 32b2a7394f..7bcdb0ba2d 100644 --- a/googlemock/src/gmock.cc +++ b/googlemock/src/gmock.cc @@ -124,7 +124,7 @@ static bool ParseGoogleMockStringFlag(const char* str, const char* flag, } static bool ParseGoogleMockIntFlag(const char* str, const char* flag, - int* value) { + int32_t* value) { // Gets the value of the flag as a string. const char* const value_str = ParseGoogleMockFlagValue(str, flag, true); diff --git a/googlemock/test/gmock-generated-actions_test.cc b/googlemock/test/gmock-generated-actions_test.cc index ef39dff7c7..649061640a 100644 --- a/googlemock/test/gmock-generated-actions_test.cc +++ b/googlemock/test/gmock-generated-actions_test.cc @@ -422,6 +422,33 @@ TEST(DoAllTest, TenActions) { EXPECT_EQ('g', g); } +TEST(DoAllTest, NoArgs) { + bool ran_first = false; + Action a = + DoAll([&] { ran_first = true; }, [&] { return ran_first; }); + EXPECT_TRUE(a.Perform({})); +} + +TEST(DoAllTest, MoveOnlyArgs) { + bool ran_first = false; + Action)> a = + DoAll(InvokeWithoutArgs([&] { ran_first = true; }), + [](std::unique_ptr p) { return *p; }); + EXPECT_EQ(7, a.Perform(std::make_tuple(std::unique_ptr(new int(7))))); + EXPECT_TRUE(ran_first); +} + +TEST(DoAllTest, ImplicitlyConvertsActionArguments) { + bool ran_first = false; + // Action)> isn't an + // Action&) but can be converted. + Action)> first = [&] { ran_first = true; }; + Action)> a = + DoAll(first, [](std::vector arg) { return arg.front(); }); + EXPECT_EQ(7, a.Perform(std::make_tuple(std::vector{7}))); + EXPECT_TRUE(ran_first); +} + // The ACTION*() macros trigger warning C4100 (unreferenced formal // parameter) in MSVC with -W4. Unfortunately they cannot be fixed in // the macro definition, as the warnings are generated when the macro diff --git a/googlemock/test/gmock-generated-matchers_test.cc b/googlemock/test/gmock-generated-matchers_test.cc deleted file mode 100644 index 26c41f6832..0000000000 --- a/googlemock/test/gmock-generated-matchers_test.cc +++ /dev/null @@ -1,1321 +0,0 @@ -// Copyright 2008, Google Inc. -// 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 Google Inc. nor the names of its -// 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 -// OWNER 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. - -// Google Mock - a framework for writing C++ mock classes. -// -// This file tests the built-in matchers generated by a script. - -// Silence warning C4244: 'initializing': conversion from 'int' to 'short', -// possible loss of data and C4100, unreferenced local parameter -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4244) -# pragma warning(disable:4100) -#endif - -#include "gmock/gmock-matchers.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest-spi.h" -#include "gtest/gtest.h" - -namespace { - -using std::list; -using std::map; -using std::pair; -using std::set; -using std::stringstream; -using std::vector; -using testing::_; -using testing::AllOf; -using testing::AllOfArray; -using testing::AnyOf; -using testing::AnyOfArray; -using testing::Args; -using testing::Contains; -using testing::ElementsAre; -using testing::ElementsAreArray; -using testing::Eq; -using testing::Ge; -using testing::Gt; -using testing::Le; -using testing::Lt; -using testing::MakeMatcher; -using testing::Matcher; -using testing::MatcherInterface; -using testing::MatchResultListener; -using testing::Ne; -using testing::Not; -using testing::Pointee; -using testing::PrintToString; -using testing::Ref; -using testing::StaticAssertTypeEq; -using testing::StrEq; -using testing::Value; -using testing::internal::ElementsAreArrayMatcher; - -// Returns the description of the given matcher. -template -std::string Describe(const Matcher& m) { - stringstream ss; - m.DescribeTo(&ss); - return ss.str(); -} - -// Returns the description of the negation of the given matcher. -template -std::string DescribeNegation(const Matcher& m) { - stringstream ss; - m.DescribeNegationTo(&ss); - return ss.str(); -} - -// Returns the reason why x matches, or doesn't match, m. -template -std::string Explain(const MatcherType& m, const Value& x) { - stringstream ss; - m.ExplainMatchResultTo(x, &ss); - return ss.str(); -} - -// For testing ExplainMatchResultTo(). -class GreaterThanMatcher : public MatcherInterface { - public: - explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} - - void DescribeTo(::std::ostream* os) const override { - *os << "is greater than " << rhs_; - } - - bool MatchAndExplain(int lhs, MatchResultListener* listener) const override { - const int diff = lhs - rhs_; - if (diff > 0) { - *listener << "which is " << diff << " more than " << rhs_; - } else if (diff == 0) { - *listener << "which is the same as " << rhs_; - } else { - *listener << "which is " << -diff << " less than " << rhs_; - } - - return lhs > rhs_; - } - - private: - int rhs_; -}; - -Matcher GreaterThan(int n) { - return MakeMatcher(new GreaterThanMatcher(n)); -} - -// Tests for ElementsAre(). - -TEST(ElementsAreTest, CanDescribeExpectingNoElement) { - Matcher&> m = ElementsAre(); - EXPECT_EQ("is empty", Describe(m)); -} - -TEST(ElementsAreTest, CanDescribeExpectingOneElement) { - Matcher > m = ElementsAre(Gt(5)); - EXPECT_EQ("has 1 element that is > 5", Describe(m)); -} - -TEST(ElementsAreTest, CanDescribeExpectingManyElements) { - Matcher > m = ElementsAre(StrEq("one"), "two"); - EXPECT_EQ("has 2 elements where\n" - "element #0 is equal to \"one\",\n" - "element #1 is equal to \"two\"", Describe(m)); -} - -TEST(ElementsAreTest, CanDescribeNegationOfExpectingNoElement) { - Matcher > m = ElementsAre(); - EXPECT_EQ("isn't empty", DescribeNegation(m)); -} - -TEST(ElementsAreTest, CanDescribeNegationOfExpectingOneElment) { - Matcher& > m = ElementsAre(Gt(5)); - EXPECT_EQ("doesn't have 1 element, or\n" - "element #0 isn't > 5", DescribeNegation(m)); -} - -TEST(ElementsAreTest, CanDescribeNegationOfExpectingManyElements) { - Matcher&> m = ElementsAre("one", "two"); - EXPECT_EQ("doesn't have 2 elements, or\n" - "element #0 isn't equal to \"one\", or\n" - "element #1 isn't equal to \"two\"", DescribeNegation(m)); -} - -TEST(ElementsAreTest, DoesNotExplainTrivialMatch) { - Matcher& > m = ElementsAre(1, Ne(2)); - - list test_list; - test_list.push_back(1); - test_list.push_back(3); - EXPECT_EQ("", Explain(m, test_list)); // No need to explain anything. -} - -TEST(ElementsAreTest, ExplainsNonTrivialMatch) { - Matcher& > m = - ElementsAre(GreaterThan(1), 0, GreaterThan(2)); - - const int a[] = { 10, 0, 100 }; - vector test_vector(std::begin(a), std::end(a)); - EXPECT_EQ("whose element #0 matches, which is 9 more than 1,\n" - "and whose element #2 matches, which is 98 more than 2", - Explain(m, test_vector)); -} - -TEST(ElementsAreTest, CanExplainMismatchWrongSize) { - Matcher& > m = ElementsAre(1, 3); - - list test_list; - // No need to explain when the container is empty. - EXPECT_EQ("", Explain(m, test_list)); - - test_list.push_back(1); - EXPECT_EQ("which has 1 element", Explain(m, test_list)); -} - -TEST(ElementsAreTest, CanExplainMismatchRightSize) { - Matcher& > m = ElementsAre(1, GreaterThan(5)); - - vector v; - v.push_back(2); - v.push_back(1); - EXPECT_EQ("whose element #0 doesn't match", Explain(m, v)); - - v[0] = 1; - EXPECT_EQ("whose element #1 doesn't match, which is 4 less than 5", - Explain(m, v)); -} - -TEST(ElementsAreTest, MatchesOneElementVector) { - vector test_vector; - test_vector.push_back("test string"); - - EXPECT_THAT(test_vector, ElementsAre(StrEq("test string"))); -} - -TEST(ElementsAreTest, MatchesOneElementList) { - list test_list; - test_list.push_back("test string"); - - EXPECT_THAT(test_list, ElementsAre("test string")); -} - -TEST(ElementsAreTest, MatchesThreeElementVector) { - vector test_vector; - test_vector.push_back("one"); - test_vector.push_back("two"); - test_vector.push_back("three"); - - EXPECT_THAT(test_vector, ElementsAre("one", StrEq("two"), _)); -} - -TEST(ElementsAreTest, MatchesOneElementEqMatcher) { - vector test_vector; - test_vector.push_back(4); - - EXPECT_THAT(test_vector, ElementsAre(Eq(4))); -} - -TEST(ElementsAreTest, MatchesOneElementAnyMatcher) { - vector test_vector; - test_vector.push_back(4); - - EXPECT_THAT(test_vector, ElementsAre(_)); -} - -TEST(ElementsAreTest, MatchesOneElementValue) { - vector test_vector; - test_vector.push_back(4); - - EXPECT_THAT(test_vector, ElementsAre(4)); -} - -TEST(ElementsAreTest, MatchesThreeElementsMixedMatchers) { - vector test_vector; - test_vector.push_back(1); - test_vector.push_back(2); - test_vector.push_back(3); - - EXPECT_THAT(test_vector, ElementsAre(1, Eq(2), _)); -} - -TEST(ElementsAreTest, MatchesTenElementVector) { - const int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - vector test_vector(std::begin(a), std::end(a)); - - EXPECT_THAT(test_vector, - // The element list can contain values and/or matchers - // of different types. - ElementsAre(0, Ge(0), _, 3, 4, Ne(2), Eq(6), 7, 8, _)); -} - -TEST(ElementsAreTest, DoesNotMatchWrongSize) { - vector test_vector; - test_vector.push_back("test string"); - test_vector.push_back("test string"); - - Matcher > m = ElementsAre(StrEq("test string")); - EXPECT_FALSE(m.Matches(test_vector)); -} - -TEST(ElementsAreTest, DoesNotMatchWrongValue) { - vector test_vector; - test_vector.push_back("other string"); - - Matcher > m = ElementsAre(StrEq("test string")); - EXPECT_FALSE(m.Matches(test_vector)); -} - -TEST(ElementsAreTest, DoesNotMatchWrongOrder) { - vector test_vector; - test_vector.push_back("one"); - test_vector.push_back("three"); - test_vector.push_back("two"); - - Matcher > m = - ElementsAre(StrEq("one"), StrEq("two"), StrEq("three")); - EXPECT_FALSE(m.Matches(test_vector)); -} - -TEST(ElementsAreTest, WorksForNestedContainer) { - constexpr std::array strings = {{"Hi", "world"}}; - - vector > nested; - for (size_t i = 0; i < strings.size(); i++) { - nested.push_back(list(strings[i], strings[i] + strlen(strings[i]))); - } - - EXPECT_THAT(nested, ElementsAre(ElementsAre('H', Ne('e')), - ElementsAre('w', 'o', _, _, 'd'))); - EXPECT_THAT(nested, Not(ElementsAre(ElementsAre('H', 'e'), - ElementsAre('w', 'o', _, _, 'd')))); -} - -TEST(ElementsAreTest, WorksWithByRefElementMatchers) { - int a[] = { 0, 1, 2 }; - vector v(std::begin(a), std::end(a)); - - EXPECT_THAT(v, ElementsAre(Ref(v[0]), Ref(v[1]), Ref(v[2]))); - EXPECT_THAT(v, Not(ElementsAre(Ref(v[0]), Ref(v[1]), Ref(a[2])))); -} - -TEST(ElementsAreTest, WorksWithContainerPointerUsingPointee) { - int a[] = { 0, 1, 2 }; - vector v(std::begin(a), std::end(a)); - - EXPECT_THAT(&v, Pointee(ElementsAre(0, 1, _))); - EXPECT_THAT(&v, Not(Pointee(ElementsAre(0, _, 3)))); -} - -TEST(ElementsAreTest, WorksWithNativeArrayPassedByReference) { - int array[] = { 0, 1, 2 }; - EXPECT_THAT(array, ElementsAre(0, 1, _)); - EXPECT_THAT(array, Not(ElementsAre(1, _, _))); - EXPECT_THAT(array, Not(ElementsAre(0, _))); -} - -class NativeArrayPassedAsPointerAndSize { - public: - NativeArrayPassedAsPointerAndSize() {} - - MOCK_METHOD2(Helper, void(int* array, int size)); - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(NativeArrayPassedAsPointerAndSize); -}; - -TEST(ElementsAreTest, WorksWithNativeArrayPassedAsPointerAndSize) { - int array[] = { 0, 1 }; - ::std::tuple array_as_tuple(array, 2); - EXPECT_THAT(array_as_tuple, ElementsAre(0, 1)); - EXPECT_THAT(array_as_tuple, Not(ElementsAre(0))); - - NativeArrayPassedAsPointerAndSize helper; - EXPECT_CALL(helper, Helper(_, _)) - .With(ElementsAre(0, 1)); - helper.Helper(array, 2); -} - -TEST(ElementsAreTest, WorksWithTwoDimensionalNativeArray) { - const char a2[][3] = { "hi", "lo" }; - EXPECT_THAT(a2, ElementsAre(ElementsAre('h', 'i', '\0'), - ElementsAre('l', 'o', '\0'))); - EXPECT_THAT(a2, ElementsAre(StrEq("hi"), StrEq("lo"))); - EXPECT_THAT(a2, ElementsAre(Not(ElementsAre('h', 'o', '\0')), - ElementsAre('l', 'o', '\0'))); -} - -TEST(ElementsAreTest, AcceptsStringLiteral) { - std::string array[] = {"hi", "one", "two"}; - EXPECT_THAT(array, ElementsAre("hi", "one", "two")); - EXPECT_THAT(array, Not(ElementsAre("hi", "one", "too"))); -} - -// Declared here with the size unknown. Defined AFTER the following test. -extern const char kHi[]; - -TEST(ElementsAreTest, AcceptsArrayWithUnknownSize) { - // The size of kHi is not known in this test, but ElementsAre() should - // still accept it. - - std::string array1[] = {"hi"}; - EXPECT_THAT(array1, ElementsAre(kHi)); - - std::string array2[] = {"ho"}; - EXPECT_THAT(array2, Not(ElementsAre(kHi))); -} - -const char kHi[] = "hi"; - -TEST(ElementsAreTest, MakesCopyOfArguments) { - int x = 1; - int y = 2; - // This should make a copy of x and y. - ::testing::internal::ElementsAreMatcher > - polymorphic_matcher = ElementsAre(x, y); - // Changing x and y now shouldn't affect the meaning of the above matcher. - x = y = 0; - const int array1[] = { 1, 2 }; - EXPECT_THAT(array1, polymorphic_matcher); - const int array2[] = { 0, 0 }; - EXPECT_THAT(array2, Not(polymorphic_matcher)); -} - - -// Tests for ElementsAreArray(). Since ElementsAreArray() shares most -// of the implementation with ElementsAre(), we don't test it as -// thoroughly here. - -TEST(ElementsAreArrayTest, CanBeCreatedWithValueArray) { - const int a[] = { 1, 2, 3 }; - - vector test_vector(std::begin(a), std::end(a)); - EXPECT_THAT(test_vector, ElementsAreArray(a)); - - test_vector[2] = 0; - EXPECT_THAT(test_vector, Not(ElementsAreArray(a))); -} - -TEST(ElementsAreArrayTest, CanBeCreatedWithArraySize) { - std::array a = {{"one", "two", "three"}}; - - vector test_vector(std::begin(a), std::end(a)); - EXPECT_THAT(test_vector, ElementsAreArray(a.data(), a.size())); - - const char** p = a.data(); - test_vector[0] = "1"; - EXPECT_THAT(test_vector, Not(ElementsAreArray(p, a.size()))); -} - -TEST(ElementsAreArrayTest, CanBeCreatedWithoutArraySize) { - const char* a[] = { "one", "two", "three" }; - - vector test_vector(std::begin(a), std::end(a)); - EXPECT_THAT(test_vector, ElementsAreArray(a)); - - test_vector[0] = "1"; - EXPECT_THAT(test_vector, Not(ElementsAreArray(a))); -} - -TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherArray) { - const Matcher kMatcherArray[] = {StrEq("one"), StrEq("two"), - StrEq("three")}; - - vector test_vector; - test_vector.push_back("one"); - test_vector.push_back("two"); - test_vector.push_back("three"); - EXPECT_THAT(test_vector, ElementsAreArray(kMatcherArray)); - - test_vector.push_back("three"); - EXPECT_THAT(test_vector, Not(ElementsAreArray(kMatcherArray))); -} - -TEST(ElementsAreArrayTest, CanBeCreatedWithVector) { - const int a[] = { 1, 2, 3 }; - vector test_vector(std::begin(a), std::end(a)); - const vector expected(std::begin(a), std::end(a)); - EXPECT_THAT(test_vector, ElementsAreArray(expected)); - test_vector.push_back(4); - EXPECT_THAT(test_vector, Not(ElementsAreArray(expected))); -} - - -TEST(ElementsAreArrayTest, TakesInitializerList) { - const int a[5] = { 1, 2, 3, 4, 5 }; - EXPECT_THAT(a, ElementsAreArray({ 1, 2, 3, 4, 5 })); - EXPECT_THAT(a, Not(ElementsAreArray({ 1, 2, 3, 5, 4 }))); - EXPECT_THAT(a, Not(ElementsAreArray({ 1, 2, 3, 4, 6 }))); -} - -TEST(ElementsAreArrayTest, TakesInitializerListOfCStrings) { - const std::string a[5] = {"a", "b", "c", "d", "e"}; - EXPECT_THAT(a, ElementsAreArray({ "a", "b", "c", "d", "e" })); - EXPECT_THAT(a, Not(ElementsAreArray({ "a", "b", "c", "e", "d" }))); - EXPECT_THAT(a, Not(ElementsAreArray({ "a", "b", "c", "d", "ef" }))); -} - -TEST(ElementsAreArrayTest, TakesInitializerListOfSameTypedMatchers) { - const int a[5] = { 1, 2, 3, 4, 5 }; - EXPECT_THAT(a, ElementsAreArray( - { Eq(1), Eq(2), Eq(3), Eq(4), Eq(5) })); - EXPECT_THAT(a, Not(ElementsAreArray( - { Eq(1), Eq(2), Eq(3), Eq(4), Eq(6) }))); -} - -TEST(ElementsAreArrayTest, - TakesInitializerListOfDifferentTypedMatchers) { - const int a[5] = { 1, 2, 3, 4, 5 }; - // The compiler cannot infer the type of the initializer list if its - // elements have different types. We must explicitly specify the - // unified element type in this case. - EXPECT_THAT(a, ElementsAreArray >( - { Eq(1), Ne(-2), Ge(3), Le(4), Eq(5) })); - EXPECT_THAT(a, Not(ElementsAreArray >( - { Eq(1), Ne(-2), Ge(3), Le(4), Eq(6) }))); -} - - -TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherVector) { - const int a[] = { 1, 2, 3 }; - const Matcher kMatchers[] = { Eq(1), Eq(2), Eq(3) }; - vector test_vector(std::begin(a), std::end(a)); - const vector> expected(std::begin(kMatchers), - std::end(kMatchers)); - EXPECT_THAT(test_vector, ElementsAreArray(expected)); - test_vector.push_back(4); - EXPECT_THAT(test_vector, Not(ElementsAreArray(expected))); -} - -TEST(ElementsAreArrayTest, CanBeCreatedWithIteratorRange) { - const int a[] = { 1, 2, 3 }; - const vector test_vector(std::begin(a), std::end(a)); - const vector expected(std::begin(a), std::end(a)); - EXPECT_THAT(test_vector, ElementsAreArray(expected.begin(), expected.end())); - // Pointers are iterators, too. - EXPECT_THAT(test_vector, ElementsAreArray(std::begin(a), std::end(a))); - // The empty range of NULL pointers should also be okay. - int* const null_int = nullptr; - EXPECT_THAT(test_vector, Not(ElementsAreArray(null_int, null_int))); - EXPECT_THAT((vector()), ElementsAreArray(null_int, null_int)); -} - -// Since ElementsAre() and ElementsAreArray() share much of the -// implementation, we only do a sanity test for native arrays here. -TEST(ElementsAreArrayTest, WorksWithNativeArray) { - ::std::string a[] = { "hi", "ho" }; - ::std::string b[] = { "hi", "ho" }; - - EXPECT_THAT(a, ElementsAreArray(b)); - EXPECT_THAT(a, ElementsAreArray(b, 2)); - EXPECT_THAT(a, Not(ElementsAreArray(b, 1))); -} - -TEST(ElementsAreArrayTest, SourceLifeSpan) { - const int a[] = { 1, 2, 3 }; - vector test_vector(std::begin(a), std::end(a)); - vector expect(std::begin(a), std::end(a)); - ElementsAreArrayMatcher matcher_maker = - ElementsAreArray(expect.begin(), expect.end()); - EXPECT_THAT(test_vector, matcher_maker); - // Changing in place the values that initialized matcher_maker should not - // affect matcher_maker anymore. It should have made its own copy of them. - typedef vector::iterator Iter; - for (Iter it = expect.begin(); it != expect.end(); ++it) { *it += 10; } - EXPECT_THAT(test_vector, matcher_maker); - test_vector.push_back(3); - EXPECT_THAT(test_vector, Not(matcher_maker)); -} - -// Tests for the MATCHER*() macro family. - -// Tests that a simple MATCHER() definition works. - -MATCHER(IsEven, "") { return (arg % 2) == 0; } - -TEST(MatcherMacroTest, Works) { - const Matcher m = IsEven(); - EXPECT_TRUE(m.Matches(6)); - EXPECT_FALSE(m.Matches(7)); - - EXPECT_EQ("is even", Describe(m)); - EXPECT_EQ("not (is even)", DescribeNegation(m)); - EXPECT_EQ("", Explain(m, 6)); - EXPECT_EQ("", Explain(m, 7)); -} - -// This also tests that the description string can reference 'negation'. -MATCHER(IsEven2, negation ? "is odd" : "is even") { - if ((arg % 2) == 0) { - // Verifies that we can stream to result_listener, a listener - // supplied by the MATCHER macro implicitly. - *result_listener << "OK"; - return true; - } else { - *result_listener << "% 2 == " << (arg % 2); - return false; - } -} - -// This also tests that the description string can reference matcher -// parameters. -MATCHER_P2(EqSumOf, x, y, std::string(negation ? "doesn't equal" : "equals") + - " the sum of " + PrintToString(x) + " and " + - PrintToString(y)) { - if (arg == (x + y)) { - *result_listener << "OK"; - return true; - } else { - // Verifies that we can stream to the underlying stream of - // result_listener. - if (result_listener->stream() != nullptr) { - *result_listener->stream() << "diff == " << (x + y - arg); - } - return false; - } -} - -// Tests that the matcher description can reference 'negation' and the -// matcher parameters. -TEST(MatcherMacroTest, DescriptionCanReferenceNegationAndParameters) { - const Matcher m1 = IsEven2(); - EXPECT_EQ("is even", Describe(m1)); - EXPECT_EQ("is odd", DescribeNegation(m1)); - - const Matcher m2 = EqSumOf(5, 9); - EXPECT_EQ("equals the sum of 5 and 9", Describe(m2)); - EXPECT_EQ("doesn't equal the sum of 5 and 9", DescribeNegation(m2)); -} - -// Tests explaining match result in a MATCHER* macro. -TEST(MatcherMacroTest, CanExplainMatchResult) { - const Matcher m1 = IsEven2(); - EXPECT_EQ("OK", Explain(m1, 4)); - EXPECT_EQ("% 2 == 1", Explain(m1, 5)); - - const Matcher m2 = EqSumOf(1, 2); - EXPECT_EQ("OK", Explain(m2, 3)); - EXPECT_EQ("diff == -1", Explain(m2, 4)); -} - -// Tests that the body of MATCHER() can reference the type of the -// value being matched. - -MATCHER(IsEmptyString, "") { - StaticAssertTypeEq< ::std::string, arg_type>(); - return arg == ""; -} - -MATCHER(IsEmptyStringByRef, "") { - StaticAssertTypeEq(); - return arg == ""; -} - -TEST(MatcherMacroTest, CanReferenceArgType) { - const Matcher< ::std::string> m1 = IsEmptyString(); - EXPECT_TRUE(m1.Matches("")); - - const Matcher m2 = IsEmptyStringByRef(); - EXPECT_TRUE(m2.Matches("")); -} - -// Tests that MATCHER() can be used in a namespace. - -namespace matcher_test { -MATCHER(IsOdd, "") { return (arg % 2) != 0; } -} // namespace matcher_test - -TEST(MatcherMacroTest, WorksInNamespace) { - Matcher m = matcher_test::IsOdd(); - EXPECT_FALSE(m.Matches(4)); - EXPECT_TRUE(m.Matches(5)); -} - -// Tests that Value() can be used to compose matchers. -MATCHER(IsPositiveOdd, "") { - return Value(arg, matcher_test::IsOdd()) && arg > 0; -} - -TEST(MatcherMacroTest, CanBeComposedUsingValue) { - EXPECT_THAT(3, IsPositiveOdd()); - EXPECT_THAT(4, Not(IsPositiveOdd())); - EXPECT_THAT(-1, Not(IsPositiveOdd())); -} - -// Tests that a simple MATCHER_P() definition works. - -MATCHER_P(IsGreaterThan32And, n, "") { return arg > 32 && arg > n; } - -TEST(MatcherPMacroTest, Works) { - const Matcher m = IsGreaterThan32And(5); - EXPECT_TRUE(m.Matches(36)); - EXPECT_FALSE(m.Matches(5)); - - EXPECT_EQ("is greater than 32 and 5", Describe(m)); - EXPECT_EQ("not (is greater than 32 and 5)", DescribeNegation(m)); - EXPECT_EQ("", Explain(m, 36)); - EXPECT_EQ("", Explain(m, 5)); -} - -// Tests that the description is calculated correctly from the matcher name. -MATCHER_P(_is_Greater_Than32and_, n, "") { return arg > 32 && arg > n; } - -TEST(MatcherPMacroTest, GeneratesCorrectDescription) { - const Matcher m = _is_Greater_Than32and_(5); - - EXPECT_EQ("is greater than 32 and 5", Describe(m)); - EXPECT_EQ("not (is greater than 32 and 5)", DescribeNegation(m)); - EXPECT_EQ("", Explain(m, 36)); - EXPECT_EQ("", Explain(m, 5)); -} - -// Tests that a MATCHER_P matcher can be explicitly instantiated with -// a reference parameter type. - -class UncopyableFoo { - public: - explicit UncopyableFoo(char value) : value_(value) {} - private: - UncopyableFoo(const UncopyableFoo&); - void operator=(const UncopyableFoo&); - - char value_; -}; - -MATCHER_P(ReferencesUncopyable, variable, "") { return &arg == &variable; } - -TEST(MatcherPMacroTest, WorksWhenExplicitlyInstantiatedWithReference) { - UncopyableFoo foo1('1'), foo2('2'); - const Matcher m = - ReferencesUncopyable(foo1); - - EXPECT_TRUE(m.Matches(foo1)); - EXPECT_FALSE(m.Matches(foo2)); - - // We don't want the address of the parameter printed, as most - // likely it will just annoy the user. If the address is - // interesting, the user should consider passing the parameter by - // pointer instead. - EXPECT_EQ("references uncopyable 1-byte object <31>", Describe(m)); -} - - -// Tests that the body of MATCHER_Pn() can reference the parameter -// types. - -MATCHER_P3(ParamTypesAreIntLongAndChar, foo, bar, baz, "") { - StaticAssertTypeEq(); - StaticAssertTypeEq(); // NOLINT - StaticAssertTypeEq(); - return arg == 0; -} - -TEST(MatcherPnMacroTest, CanReferenceParamTypes) { - EXPECT_THAT(0, ParamTypesAreIntLongAndChar(10, 20L, 'a')); -} - -// Tests that a MATCHER_Pn matcher can be explicitly instantiated with -// reference parameter types. - -MATCHER_P2(ReferencesAnyOf, variable1, variable2, "") { - return &arg == &variable1 || &arg == &variable2; -} - -TEST(MatcherPnMacroTest, WorksWhenExplicitlyInstantiatedWithReferences) { - UncopyableFoo foo1('1'), foo2('2'), foo3('3'); - const Matcher const_m = - ReferencesAnyOf(foo1, foo2); - - EXPECT_TRUE(const_m.Matches(foo1)); - EXPECT_TRUE(const_m.Matches(foo2)); - EXPECT_FALSE(const_m.Matches(foo3)); - - const Matcher m = - ReferencesAnyOf(foo1, foo2); - - EXPECT_TRUE(m.Matches(foo1)); - EXPECT_TRUE(m.Matches(foo2)); - EXPECT_FALSE(m.Matches(foo3)); -} - -TEST(MatcherPnMacroTest, - GeneratesCorretDescriptionWhenExplicitlyInstantiatedWithReferences) { - UncopyableFoo foo1('1'), foo2('2'); - const Matcher m = - ReferencesAnyOf(foo1, foo2); - - // We don't want the addresses of the parameters printed, as most - // likely they will just annoy the user. If the addresses are - // interesting, the user should consider passing the parameters by - // pointers instead. - EXPECT_EQ("references any of (1-byte object <31>, 1-byte object <32>)", - Describe(m)); -} - -// Tests that a simple MATCHER_P2() definition works. - -MATCHER_P2(IsNotInClosedRange, low, hi, "") { return arg < low || arg > hi; } - -TEST(MatcherPnMacroTest, Works) { - const Matcher m = IsNotInClosedRange(10, 20); // NOLINT - EXPECT_TRUE(m.Matches(36L)); - EXPECT_FALSE(m.Matches(15L)); - - EXPECT_EQ("is not in closed range (10, 20)", Describe(m)); - EXPECT_EQ("not (is not in closed range (10, 20))", DescribeNegation(m)); - EXPECT_EQ("", Explain(m, 36L)); - EXPECT_EQ("", Explain(m, 15L)); -} - -// Tests that MATCHER*() definitions can be overloaded on the number -// of parameters; also tests MATCHER_Pn() where n >= 3. - -MATCHER(EqualsSumOf, "") { return arg == 0; } -MATCHER_P(EqualsSumOf, a, "") { return arg == a; } -MATCHER_P2(EqualsSumOf, a, b, "") { return arg == a + b; } -MATCHER_P3(EqualsSumOf, a, b, c, "") { return arg == a + b + c; } -MATCHER_P4(EqualsSumOf, a, b, c, d, "") { return arg == a + b + c + d; } -MATCHER_P5(EqualsSumOf, a, b, c, d, e, "") { return arg == a + b + c + d + e; } -MATCHER_P6(EqualsSumOf, a, b, c, d, e, f, "") { - return arg == a + b + c + d + e + f; -} -MATCHER_P7(EqualsSumOf, a, b, c, d, e, f, g, "") { - return arg == a + b + c + d + e + f + g; -} -MATCHER_P8(EqualsSumOf, a, b, c, d, e, f, g, h, "") { - return arg == a + b + c + d + e + f + g + h; -} -MATCHER_P9(EqualsSumOf, a, b, c, d, e, f, g, h, i, "") { - return arg == a + b + c + d + e + f + g + h + i; -} -MATCHER_P10(EqualsSumOf, a, b, c, d, e, f, g, h, i, j, "") { - return arg == a + b + c + d + e + f + g + h + i + j; -} - -TEST(MatcherPnMacroTest, CanBeOverloadedOnNumberOfParameters) { - EXPECT_THAT(0, EqualsSumOf()); - EXPECT_THAT(1, EqualsSumOf(1)); - EXPECT_THAT(12, EqualsSumOf(10, 2)); - EXPECT_THAT(123, EqualsSumOf(100, 20, 3)); - EXPECT_THAT(1234, EqualsSumOf(1000, 200, 30, 4)); - EXPECT_THAT(12345, EqualsSumOf(10000, 2000, 300, 40, 5)); - EXPECT_THAT("abcdef", - EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f')); - EXPECT_THAT("abcdefg", - EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g')); - EXPECT_THAT("abcdefgh", - EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', - "h")); - EXPECT_THAT("abcdefghi", - EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', - "h", 'i')); - EXPECT_THAT("abcdefghij", - EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', - "h", 'i', ::std::string("j"))); - - EXPECT_THAT(1, Not(EqualsSumOf())); - EXPECT_THAT(-1, Not(EqualsSumOf(1))); - EXPECT_THAT(-12, Not(EqualsSumOf(10, 2))); - EXPECT_THAT(-123, Not(EqualsSumOf(100, 20, 3))); - EXPECT_THAT(-1234, Not(EqualsSumOf(1000, 200, 30, 4))); - EXPECT_THAT(-12345, Not(EqualsSumOf(10000, 2000, 300, 40, 5))); - EXPECT_THAT("abcdef ", - Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f'))); - EXPECT_THAT("abcdefg ", - Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', - 'g'))); - EXPECT_THAT("abcdefgh ", - Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', - "h"))); - EXPECT_THAT("abcdefghi ", - Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', - "h", 'i'))); - EXPECT_THAT("abcdefghij ", - Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', - "h", 'i', ::std::string("j")))); -} - -// Tests that a MATCHER_Pn() definition can be instantiated with any -// compatible parameter types. -TEST(MatcherPnMacroTest, WorksForDifferentParameterTypes) { - EXPECT_THAT(123, EqualsSumOf(100L, 20, static_cast(3))); - EXPECT_THAT("abcd", EqualsSumOf(::std::string("a"), "b", 'c', "d")); - - EXPECT_THAT(124, Not(EqualsSumOf(100L, 20, static_cast(3)))); - EXPECT_THAT("abcde", Not(EqualsSumOf(::std::string("a"), "b", 'c', "d"))); -} - -// Tests that the matcher body can promote the parameter types. - -MATCHER_P2(EqConcat, prefix, suffix, "") { - // The following lines promote the two parameters to desired types. - std::string prefix_str(prefix); - char suffix_char = static_cast(suffix); - return arg == prefix_str + suffix_char; -} - -TEST(MatcherPnMacroTest, SimpleTypePromotion) { - Matcher no_promo = - EqConcat(std::string("foo"), 't'); - Matcher promo = - EqConcat("foo", static_cast('t')); - EXPECT_FALSE(no_promo.Matches("fool")); - EXPECT_FALSE(promo.Matches("fool")); - EXPECT_TRUE(no_promo.Matches("foot")); - EXPECT_TRUE(promo.Matches("foot")); -} - -// Verifies the type of a MATCHER*. - -TEST(MatcherPnMacroTest, TypesAreCorrect) { - // EqualsSumOf() must be assignable to a EqualsSumOfMatcher variable. - EqualsSumOfMatcher a0 = EqualsSumOf(); - - // EqualsSumOf(1) must be assignable to a EqualsSumOfMatcherP variable. - EqualsSumOfMatcherP a1 = EqualsSumOf(1); - - // EqualsSumOf(p1, ..., pk) must be assignable to a EqualsSumOfMatcherPk - // variable, and so on. - EqualsSumOfMatcherP2 a2 = EqualsSumOf(1, '2'); - EqualsSumOfMatcherP3 a3 = EqualsSumOf(1, 2, '3'); - EqualsSumOfMatcherP4 a4 = EqualsSumOf(1, 2, 3, '4'); - EqualsSumOfMatcherP5 a5 = - EqualsSumOf(1, 2, 3, 4, '5'); - EqualsSumOfMatcherP6 a6 = - EqualsSumOf(1, 2, 3, 4, 5, '6'); - EqualsSumOfMatcherP7 a7 = - EqualsSumOf(1, 2, 3, 4, 5, 6, '7'); - EqualsSumOfMatcherP8 a8 = - EqualsSumOf(1, 2, 3, 4, 5, 6, 7, '8'); - EqualsSumOfMatcherP9 a9 = - EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, '9'); - EqualsSumOfMatcherP10 a10 = - EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); - - // Avoid "unused variable" warnings. - (void)a0; - (void)a1; - (void)a2; - (void)a3; - (void)a4; - (void)a5; - (void)a6; - (void)a7; - (void)a8; - (void)a9; - (void)a10; -} - -// Tests that matcher-typed parameters can be used in Value() inside a -// MATCHER_Pn definition. - -// Succeeds if arg matches exactly 2 of the 3 matchers. -MATCHER_P3(TwoOf, m1, m2, m3, "") { - const int count = static_cast(Value(arg, m1)) - + static_cast(Value(arg, m2)) + static_cast(Value(arg, m3)); - return count == 2; -} - -TEST(MatcherPnMacroTest, CanUseMatcherTypedParameterInValue) { - EXPECT_THAT(42, TwoOf(Gt(0), Lt(50), Eq(10))); - EXPECT_THAT(0, Not(TwoOf(Gt(-1), Lt(1), Eq(0)))); -} - -// Tests Contains(). - -TEST(ContainsTest, ListMatchesWhenElementIsInContainer) { - list some_list; - some_list.push_back(3); - some_list.push_back(1); - some_list.push_back(2); - EXPECT_THAT(some_list, Contains(1)); - EXPECT_THAT(some_list, Contains(Gt(2.5))); - EXPECT_THAT(some_list, Contains(Eq(2.0f))); - - list another_list; - another_list.push_back("fee"); - another_list.push_back("fie"); - another_list.push_back("foe"); - another_list.push_back("fum"); - EXPECT_THAT(another_list, Contains(std::string("fee"))); -} - -TEST(ContainsTest, ListDoesNotMatchWhenElementIsNotInContainer) { - list some_list; - some_list.push_back(3); - some_list.push_back(1); - EXPECT_THAT(some_list, Not(Contains(4))); -} - -TEST(ContainsTest, SetMatchesWhenElementIsInContainer) { - set some_set; - some_set.insert(3); - some_set.insert(1); - some_set.insert(2); - EXPECT_THAT(some_set, Contains(Eq(1.0))); - EXPECT_THAT(some_set, Contains(Eq(3.0f))); - EXPECT_THAT(some_set, Contains(2)); - - set another_set; - another_set.insert("fee"); - another_set.insert("fie"); - another_set.insert("foe"); - another_set.insert("fum"); - EXPECT_THAT(another_set, Contains(Eq(std::string("fum")))); -} - -TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { - set some_set; - some_set.insert(3); - some_set.insert(1); - EXPECT_THAT(some_set, Not(Contains(4))); - - set c_string_set; - c_string_set.insert("hello"); - EXPECT_THAT(c_string_set, Not(Contains(std::string("hello").c_str()))); -} - -TEST(ContainsTest, ExplainsMatchResultCorrectly) { - const int a[2] = { 1, 2 }; - Matcher m = Contains(2); - EXPECT_EQ("whose element #1 matches", Explain(m, a)); - - m = Contains(3); - EXPECT_EQ("", Explain(m, a)); - - m = Contains(GreaterThan(0)); - EXPECT_EQ("whose element #0 matches, which is 1 more than 0", Explain(m, a)); - - m = Contains(GreaterThan(10)); - EXPECT_EQ("", Explain(m, a)); -} - -TEST(ContainsTest, DescribesItselfCorrectly) { - Matcher > m = Contains(1); - EXPECT_EQ("contains at least one element that is equal to 1", Describe(m)); - - Matcher > m2 = Not(m); - EXPECT_EQ("doesn't contain any element that is equal to 1", Describe(m2)); -} - -TEST(ContainsTest, MapMatchesWhenElementIsInContainer) { - map my_map; - const char* bar = "a string"; - my_map[bar] = 2; - EXPECT_THAT(my_map, Contains(pair(bar, 2))); - - map another_map; - another_map["fee"] = 1; - another_map["fie"] = 2; - another_map["foe"] = 3; - another_map["fum"] = 4; - EXPECT_THAT(another_map, - Contains(pair(std::string("fee"), 1))); - EXPECT_THAT(another_map, Contains(pair("fie", 2))); -} - -TEST(ContainsTest, MapDoesNotMatchWhenElementIsNotInContainer) { - map some_map; - some_map[1] = 11; - some_map[2] = 22; - EXPECT_THAT(some_map, Not(Contains(pair(2, 23)))); -} - -TEST(ContainsTest, ArrayMatchesWhenElementIsInContainer) { - const char* string_array[] = { "fee", "fie", "foe", "fum" }; - EXPECT_THAT(string_array, Contains(Eq(std::string("fum")))); -} - -TEST(ContainsTest, ArrayDoesNotMatchWhenElementIsNotInContainer) { - int int_array[] = { 1, 2, 3, 4 }; - EXPECT_THAT(int_array, Not(Contains(5))); -} - -TEST(ContainsTest, AcceptsMatcher) { - const int a[] = { 1, 2, 3 }; - EXPECT_THAT(a, Contains(Gt(2))); - EXPECT_THAT(a, Not(Contains(Gt(4)))); -} - -TEST(ContainsTest, WorksForNativeArrayAsTuple) { - const int a[] = { 1, 2 }; - const int* const pointer = a; - EXPECT_THAT(std::make_tuple(pointer, 2), Contains(1)); - EXPECT_THAT(std::make_tuple(pointer, 2), Not(Contains(Gt(3)))); -} - -TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { - int a[][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; - EXPECT_THAT(a, Contains(ElementsAre(4, 5, 6))); - EXPECT_THAT(a, Contains(Contains(5))); - EXPECT_THAT(a, Not(Contains(ElementsAre(3, 4, 5)))); - EXPECT_THAT(a, Contains(Not(Contains(5)))); -} - -TEST(AllOfArrayTest, BasicForms) { - // Iterator - std::vector v0{}; - std::vector v1{1}; - std::vector v2{2, 3}; - std::vector v3{4, 4, 4}; - EXPECT_THAT(0, AllOfArray(v0.begin(), v0.end())); - EXPECT_THAT(1, AllOfArray(v1.begin(), v1.end())); - EXPECT_THAT(2, Not(AllOfArray(v1.begin(), v1.end()))); - EXPECT_THAT(3, Not(AllOfArray(v2.begin(), v2.end()))); - EXPECT_THAT(4, AllOfArray(v3.begin(), v3.end())); - // Pointer + size - int ar[6] = {1, 2, 3, 4, 4, 4}; - EXPECT_THAT(0, AllOfArray(ar, 0)); - EXPECT_THAT(1, AllOfArray(ar, 1)); - EXPECT_THAT(2, Not(AllOfArray(ar, 1))); - EXPECT_THAT(3, Not(AllOfArray(ar + 1, 3))); - EXPECT_THAT(4, AllOfArray(ar + 3, 3)); - // Array - // int ar0[0]; Not usable - int ar1[1] = {1}; - int ar2[2] = {2, 3}; - int ar3[3] = {4, 4, 4}; - // EXPECT_THAT(0, Not(AllOfArray(ar0))); // Cannot work - EXPECT_THAT(1, AllOfArray(ar1)); - EXPECT_THAT(2, Not(AllOfArray(ar1))); - EXPECT_THAT(3, Not(AllOfArray(ar2))); - EXPECT_THAT(4, AllOfArray(ar3)); - // Container - EXPECT_THAT(0, AllOfArray(v0)); - EXPECT_THAT(1, AllOfArray(v1)); - EXPECT_THAT(2, Not(AllOfArray(v1))); - EXPECT_THAT(3, Not(AllOfArray(v2))); - EXPECT_THAT(4, AllOfArray(v3)); - // Initializer - EXPECT_THAT(0, AllOfArray({})); // Requires template arg. - EXPECT_THAT(1, AllOfArray({1})); - EXPECT_THAT(2, Not(AllOfArray({1}))); - EXPECT_THAT(3, Not(AllOfArray({2, 3}))); - EXPECT_THAT(4, AllOfArray({4, 4, 4})); -} - -TEST(AllOfArrayTest, Matchers) { - // vector - std::vector> matchers{Ge(1), Lt(2)}; - EXPECT_THAT(0, Not(AllOfArray(matchers))); - EXPECT_THAT(1, AllOfArray(matchers)); - EXPECT_THAT(2, Not(AllOfArray(matchers))); - // initializer_list - EXPECT_THAT(0, Not(AllOfArray({Ge(0), Ge(1)}))); - EXPECT_THAT(1, AllOfArray({Ge(0), Ge(1)})); -} - -TEST(AnyOfArrayTest, BasicForms) { - // Iterator - std::vector v0{}; - std::vector v1{1}; - std::vector v2{2, 3}; - EXPECT_THAT(0, Not(AnyOfArray(v0.begin(), v0.end()))); - EXPECT_THAT(1, AnyOfArray(v1.begin(), v1.end())); - EXPECT_THAT(2, Not(AnyOfArray(v1.begin(), v1.end()))); - EXPECT_THAT(3, AnyOfArray(v2.begin(), v2.end())); - EXPECT_THAT(4, Not(AnyOfArray(v2.begin(), v2.end()))); - // Pointer + size - int ar[3] = {1, 2, 3}; - EXPECT_THAT(0, Not(AnyOfArray(ar, 0))); - EXPECT_THAT(1, AnyOfArray(ar, 1)); - EXPECT_THAT(2, Not(AnyOfArray(ar, 1))); - EXPECT_THAT(3, AnyOfArray(ar + 1, 2)); - EXPECT_THAT(4, Not(AnyOfArray(ar + 1, 2))); - // Array - // int ar0[0]; Not usable - int ar1[1] = {1}; - int ar2[2] = {2, 3}; - // EXPECT_THAT(0, Not(AnyOfArray(ar0))); // Cannot work - EXPECT_THAT(1, AnyOfArray(ar1)); - EXPECT_THAT(2, Not(AnyOfArray(ar1))); - EXPECT_THAT(3, AnyOfArray(ar2)); - EXPECT_THAT(4, Not(AnyOfArray(ar2))); - // Container - EXPECT_THAT(0, Not(AnyOfArray(v0))); - EXPECT_THAT(1, AnyOfArray(v1)); - EXPECT_THAT(2, Not(AnyOfArray(v1))); - EXPECT_THAT(3, AnyOfArray(v2)); - EXPECT_THAT(4, Not(AnyOfArray(v2))); - // Initializer - EXPECT_THAT(0, Not(AnyOfArray({}))); // Requires template arg. - EXPECT_THAT(1, AnyOfArray({1})); - EXPECT_THAT(2, Not(AnyOfArray({1}))); - EXPECT_THAT(3, AnyOfArray({2, 3})); - EXPECT_THAT(4, Not(AnyOfArray({2, 3}))); -} - -TEST(AnyOfArrayTest, Matchers) { - // We negate test AllOfArrayTest.Matchers. - // vector - std::vector> matchers{Lt(1), Ge(2)}; - EXPECT_THAT(0, AnyOfArray(matchers)); - EXPECT_THAT(1, Not(AnyOfArray(matchers))); - EXPECT_THAT(2, AnyOfArray(matchers)); - // initializer_list - EXPECT_THAT(0, AnyOfArray({Lt(0), Lt(1)})); - EXPECT_THAT(1, Not(AllOfArray({Lt(0), Lt(1)}))); -} - -TEST(AnyOfArrayTest, ExplainsMatchResultCorrectly) { - // AnyOfArray and AllOfArry use the same underlying template-template, - // thus it is sufficient to test one here. - const std::vector v0{}; - const std::vector v1{1}; - const std::vector v2{2, 3}; - const Matcher m0 = AnyOfArray(v0); - const Matcher m1 = AnyOfArray(v1); - const Matcher m2 = AnyOfArray(v2); - EXPECT_EQ("", Explain(m0, 0)); - EXPECT_EQ("", Explain(m1, 1)); - EXPECT_EQ("", Explain(m1, 2)); - EXPECT_EQ("", Explain(m2, 3)); - EXPECT_EQ("", Explain(m2, 4)); - EXPECT_EQ("()", Describe(m0)); - EXPECT_EQ("(is equal to 1)", Describe(m1)); - EXPECT_EQ("(is equal to 2) or (is equal to 3)", Describe(m2)); - EXPECT_EQ("()", DescribeNegation(m0)); - EXPECT_EQ("(isn't equal to 1)", DescribeNegation(m1)); - EXPECT_EQ("(isn't equal to 2) and (isn't equal to 3)", DescribeNegation(m2)); - // Explain with matchers - const Matcher g1 = AnyOfArray({GreaterThan(1)}); - const Matcher g2 = AnyOfArray({GreaterThan(1), GreaterThan(2)}); - // Explains the first positiv match and all prior negative matches... - EXPECT_EQ("which is 1 less than 1", Explain(g1, 0)); - EXPECT_EQ("which is the same as 1", Explain(g1, 1)); - EXPECT_EQ("which is 1 more than 1", Explain(g1, 2)); - EXPECT_EQ("which is 1 less than 1, and which is 2 less than 2", - Explain(g2, 0)); - EXPECT_EQ("which is the same as 1, and which is 1 less than 2", - Explain(g2, 1)); - EXPECT_EQ("which is 1 more than 1", // Only the first - Explain(g2, 2)); -} - -TEST(AllOfTest, HugeMatcher) { - // Verify that using AllOf with many arguments doesn't cause - // the compiler to exceed template instantiation depth limit. - EXPECT_THAT(0, testing::AllOf(_, _, _, _, _, _, _, _, _, - testing::AllOf(_, _, _, _, _, _, _, _, _, _))); -} - -TEST(AnyOfTest, HugeMatcher) { - // Verify that using AnyOf with many arguments doesn't cause - // the compiler to exceed template instantiation depth limit. - EXPECT_THAT(0, testing::AnyOf(_, _, _, _, _, _, _, _, _, - testing::AnyOf(_, _, _, _, _, _, _, _, _, _))); -} - -namespace adl_test { - -// Verifies that the implementation of ::testing::AllOf and ::testing::AnyOf -// don't issue unqualified recursive calls. If they do, the argument dependent -// name lookup will cause AllOf/AnyOf in the 'adl_test' namespace to be found -// as a candidate and the compilation will break due to an ambiguous overload. - -// The matcher must be in the same namespace as AllOf/AnyOf to make argument -// dependent lookup find those. -MATCHER(M, "") { return true; } - -template -bool AllOf(const T1& /*t1*/, const T2& /*t2*/) { return true; } - -TEST(AllOfTest, DoesNotCallAllOfUnqualified) { - EXPECT_THAT(42, testing::AllOf( - M(), M(), M(), M(), M(), M(), M(), M(), M(), M())); -} - -template bool -AnyOf(const T1& t1, const T2& t2) { return true; } - -TEST(AnyOfTest, DoesNotCallAnyOfUnqualified) { - EXPECT_THAT(42, testing::AnyOf( - M(), M(), M(), M(), M(), M(), M(), M(), M(), M())); -} - -} // namespace adl_test - - -TEST(AllOfTest, WorksOnMoveOnlyType) { - std::unique_ptr p(new int(3)); - EXPECT_THAT(p, AllOf(Pointee(Eq(3)), Pointee(Gt(0)), Pointee(Lt(5)))); - EXPECT_THAT(p, Not(AllOf(Pointee(Eq(3)), Pointee(Gt(0)), Pointee(Lt(3))))); -} - -TEST(AnyOfTest, WorksOnMoveOnlyType) { - std::unique_ptr p(new int(3)); - EXPECT_THAT(p, AnyOf(Pointee(Eq(5)), Pointee(Lt(0)), Pointee(Lt(5)))); - EXPECT_THAT(p, Not(AnyOf(Pointee(Eq(5)), Pointee(Lt(0)), Pointee(Gt(5))))); -} - -MATCHER(IsNotNull, "") { - return arg != nullptr; -} - -// Verifies that a matcher defined using MATCHER() can work on -// move-only types. -TEST(MatcherMacroTest, WorksOnMoveOnlyType) { - std::unique_ptr p(new int(3)); - EXPECT_THAT(p, IsNotNull()); - EXPECT_THAT(std::unique_ptr(), Not(IsNotNull())); -} - -MATCHER_P(UniquePointee, pointee, "") { - return *arg == pointee; -} - -// Verifies that a matcher defined using MATCHER_P*() can work on -// move-only types. -TEST(MatcherPMacroTest, WorksOnMoveOnlyType) { - std::unique_ptr p(new int(3)); - EXPECT_THAT(p, UniquePointee(3)); - EXPECT_THAT(p, Not(UniquePointee(2))); -} - - -} // namespace - -#ifdef _MSC_VER -# pragma warning(pop) -#endif diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc index a22ff34b57..0ce5b5887c 100644 --- a/googlemock/test/gmock-matchers_test.cc +++ b/googlemock/test/gmock-matchers_test.cc @@ -60,6 +60,8 @@ #include #include #include +#include +#include #include #include @@ -87,6 +89,7 @@ using std::vector; using testing::internal::DummyMatchResultListener; using testing::internal::ElementMatcherPair; using testing::internal::ElementMatcherPairs; +using testing::internal::ElementsAreArrayMatcher; using testing::internal::ExplainMatchFailureTupleTo; using testing::internal::FloatingEqMatcher; using testing::internal::FormatMatcherDescription; @@ -1640,6 +1643,147 @@ TEST(PairTest, InsideContainsUsingMap) { EXPECT_THAT(container, Not(Contains(Pair(3, _)))); } +TEST(FieldsAreTest, MatchesCorrectly) { + std::tuple p(25, "foo", .5); + + // All fields match. + EXPECT_THAT(p, FieldsAre(25, "foo", .5)); + EXPECT_THAT(p, FieldsAre(Ge(20), HasSubstr("o"), DoubleEq(.5))); + + // Some don't match. + EXPECT_THAT(p, Not(FieldsAre(26, "foo", .5))); + EXPECT_THAT(p, Not(FieldsAre(25, "fo", .5))); + EXPECT_THAT(p, Not(FieldsAre(25, "foo", .6))); +} + +TEST(FieldsAreTest, CanDescribeSelf) { + Matcher&> m1 = FieldsAre("foo", 42); + EXPECT_EQ( + "has field #0 that is equal to \"foo\"" + ", and has field #1 that is equal to 42", + Describe(m1)); + EXPECT_EQ( + "has field #0 that isn't equal to \"foo\"" + ", or has field #1 that isn't equal to 42", + DescribeNegation(m1)); +} + +TEST(FieldsAreTest, CanExplainMatchResultTo) { + // The first one that fails is the one that gives the error. + Matcher> m = + FieldsAre(GreaterThan(0), GreaterThan(0), GreaterThan(0)); + + EXPECT_EQ("whose field #0 does not match, which is 1 less than 0", + Explain(m, std::make_tuple(-1, -2, -3))); + EXPECT_EQ("whose field #1 does not match, which is 2 less than 0", + Explain(m, std::make_tuple(1, -2, -3))); + EXPECT_EQ("whose field #2 does not match, which is 3 less than 0", + Explain(m, std::make_tuple(1, 2, -3))); + + // If they all match, we get a long explanation of success. + EXPECT_EQ( + "whose all elements match, " + "where field #0 is a value which is 1 more than 0" + ", and field #1 is a value which is 2 more than 0" + ", and field #2 is a value which is 3 more than 0", + Explain(m, std::make_tuple(1, 2, 3))); + + // Only print those that have an explanation. + m = FieldsAre(GreaterThan(0), 0, GreaterThan(0)); + EXPECT_EQ( + "whose all elements match, " + "where field #0 is a value which is 1 more than 0" + ", and field #2 is a value which is 3 more than 0", + Explain(m, std::make_tuple(1, 0, 3))); + + // If only one has an explanation, then print that one. + m = FieldsAre(0, GreaterThan(0), 0); + EXPECT_EQ( + "whose all elements match, " + "where field #1 is a value which is 1 more than 0", + Explain(m, std::make_tuple(0, 1, 0))); +} + +#if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 201606 +TEST(FieldsAreTest, StructuredBindings) { + // testing::FieldsAre can also match aggregates and such with C++17 and up. + struct MyType { + int i; + std::string str; + }; + EXPECT_THAT((MyType{17, "foo"}), FieldsAre(Eq(17), HasSubstr("oo"))); + + // Test all the supported arities. + struct MyVarType1 { + int a; + }; + EXPECT_THAT(MyVarType1{}, FieldsAre(0)); + struct MyVarType2 { + int a, b; + }; + EXPECT_THAT(MyVarType2{}, FieldsAre(0, 0)); + struct MyVarType3 { + int a, b, c; + }; + EXPECT_THAT(MyVarType3{}, FieldsAre(0, 0, 0)); + struct MyVarType4 { + int a, b, c, d; + }; + EXPECT_THAT(MyVarType4{}, FieldsAre(0, 0, 0, 0)); + struct MyVarType5 { + int a, b, c, d, e; + }; + EXPECT_THAT(MyVarType5{}, FieldsAre(0, 0, 0, 0, 0)); + struct MyVarType6 { + int a, b, c, d, e, f; + }; + EXPECT_THAT(MyVarType6{}, FieldsAre(0, 0, 0, 0, 0, 0)); + struct MyVarType7 { + int a, b, c, d, e, f, g; + }; + EXPECT_THAT(MyVarType7{}, FieldsAre(0, 0, 0, 0, 0, 0, 0)); + struct MyVarType8 { + int a, b, c, d, e, f, g, h; + }; + EXPECT_THAT(MyVarType8{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0)); + struct MyVarType9 { + int a, b, c, d, e, f, g, h, i; + }; + EXPECT_THAT(MyVarType9{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0)); + struct MyVarType10 { + int a, b, c, d, e, f, g, h, i, j; + }; + EXPECT_THAT(MyVarType10{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + struct MyVarType11 { + int a, b, c, d, e, f, g, h, i, j, k; + }; + EXPECT_THAT(MyVarType11{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + struct MyVarType12 { + int a, b, c, d, e, f, g, h, i, j, k, l; + }; + EXPECT_THAT(MyVarType12{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + struct MyVarType13 { + int a, b, c, d, e, f, g, h, i, j, k, l, m; + }; + EXPECT_THAT(MyVarType13{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + struct MyVarType14 { + int a, b, c, d, e, f, g, h, i, j, k, l, m, n; + }; + EXPECT_THAT(MyVarType14{}, + FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + struct MyVarType15 { + int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o; + }; + EXPECT_THAT(MyVarType15{}, + FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + struct MyVarType16 { + int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p; + }; + EXPECT_THAT(MyVarType16{}, + FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); +} +#endif + TEST(ContainsTest, WorksWithMoveOnly) { ContainerHelper helper; EXPECT_CALL(helper, Call(Contains(Pointee(2)))); @@ -6950,6 +7094,1354 @@ TEST_F(PredicateFormatterFromMatcherTest, DetectsFlakyShortCircuit) { EXPECT_EQ(expect, result.message()); } +// Tests for ElementsAre(). + +TEST(ElementsAreTest, CanDescribeExpectingNoElement) { + Matcher&> m = ElementsAre(); + EXPECT_EQ("is empty", Describe(m)); +} + +TEST(ElementsAreTest, CanDescribeExpectingOneElement) { + Matcher> m = ElementsAre(Gt(5)); + EXPECT_EQ("has 1 element that is > 5", Describe(m)); +} + +TEST(ElementsAreTest, CanDescribeExpectingManyElements) { + Matcher> m = ElementsAre(StrEq("one"), "two"); + EXPECT_EQ( + "has 2 elements where\n" + "element #0 is equal to \"one\",\n" + "element #1 is equal to \"two\"", + Describe(m)); +} + +TEST(ElementsAreTest, CanDescribeNegationOfExpectingNoElement) { + Matcher> m = ElementsAre(); + EXPECT_EQ("isn't empty", DescribeNegation(m)); +} + +TEST(ElementsAreTest, CanDescribeNegationOfExpectingOneElment) { + Matcher&> m = ElementsAre(Gt(5)); + EXPECT_EQ( + "doesn't have 1 element, or\n" + "element #0 isn't > 5", + DescribeNegation(m)); +} + +TEST(ElementsAreTest, CanDescribeNegationOfExpectingManyElements) { + Matcher&> m = ElementsAre("one", "two"); + EXPECT_EQ( + "doesn't have 2 elements, or\n" + "element #0 isn't equal to \"one\", or\n" + "element #1 isn't equal to \"two\"", + DescribeNegation(m)); +} + +TEST(ElementsAreTest, DoesNotExplainTrivialMatch) { + Matcher&> m = ElementsAre(1, Ne(2)); + + list test_list; + test_list.push_back(1); + test_list.push_back(3); + EXPECT_EQ("", Explain(m, test_list)); // No need to explain anything. +} + +TEST(ElementsAreTest, ExplainsNonTrivialMatch) { + Matcher&> m = + ElementsAre(GreaterThan(1), 0, GreaterThan(2)); + + const int a[] = {10, 0, 100}; + vector test_vector(std::begin(a), std::end(a)); + EXPECT_EQ( + "whose element #0 matches, which is 9 more than 1,\n" + "and whose element #2 matches, which is 98 more than 2", + Explain(m, test_vector)); +} + +TEST(ElementsAreTest, CanExplainMismatchWrongSize) { + Matcher&> m = ElementsAre(1, 3); + + list test_list; + // No need to explain when the container is empty. + EXPECT_EQ("", Explain(m, test_list)); + + test_list.push_back(1); + EXPECT_EQ("which has 1 element", Explain(m, test_list)); +} + +TEST(ElementsAreTest, CanExplainMismatchRightSize) { + Matcher&> m = ElementsAre(1, GreaterThan(5)); + + vector v; + v.push_back(2); + v.push_back(1); + EXPECT_EQ("whose element #0 doesn't match", Explain(m, v)); + + v[0] = 1; + EXPECT_EQ("whose element #1 doesn't match, which is 4 less than 5", + Explain(m, v)); +} + +TEST(ElementsAreTest, MatchesOneElementVector) { + vector test_vector; + test_vector.push_back("test string"); + + EXPECT_THAT(test_vector, ElementsAre(StrEq("test string"))); +} + +TEST(ElementsAreTest, MatchesOneElementList) { + list test_list; + test_list.push_back("test string"); + + EXPECT_THAT(test_list, ElementsAre("test string")); +} + +TEST(ElementsAreTest, MatchesThreeElementVector) { + vector test_vector; + test_vector.push_back("one"); + test_vector.push_back("two"); + test_vector.push_back("three"); + + EXPECT_THAT(test_vector, ElementsAre("one", StrEq("two"), _)); +} + +TEST(ElementsAreTest, MatchesOneElementEqMatcher) { + vector test_vector; + test_vector.push_back(4); + + EXPECT_THAT(test_vector, ElementsAre(Eq(4))); +} + +TEST(ElementsAreTest, MatchesOneElementAnyMatcher) { + vector test_vector; + test_vector.push_back(4); + + EXPECT_THAT(test_vector, ElementsAre(_)); +} + +TEST(ElementsAreTest, MatchesOneElementValue) { + vector test_vector; + test_vector.push_back(4); + + EXPECT_THAT(test_vector, ElementsAre(4)); +} + +TEST(ElementsAreTest, MatchesThreeElementsMixedMatchers) { + vector test_vector; + test_vector.push_back(1); + test_vector.push_back(2); + test_vector.push_back(3); + + EXPECT_THAT(test_vector, ElementsAre(1, Eq(2), _)); +} + +TEST(ElementsAreTest, MatchesTenElementVector) { + const int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + vector test_vector(std::begin(a), std::end(a)); + + EXPECT_THAT(test_vector, + // The element list can contain values and/or matchers + // of different types. + ElementsAre(0, Ge(0), _, 3, 4, Ne(2), Eq(6), 7, 8, _)); +} + +TEST(ElementsAreTest, DoesNotMatchWrongSize) { + vector test_vector; + test_vector.push_back("test string"); + test_vector.push_back("test string"); + + Matcher> m = ElementsAre(StrEq("test string")); + EXPECT_FALSE(m.Matches(test_vector)); +} + +TEST(ElementsAreTest, DoesNotMatchWrongValue) { + vector test_vector; + test_vector.push_back("other string"); + + Matcher> m = ElementsAre(StrEq("test string")); + EXPECT_FALSE(m.Matches(test_vector)); +} + +TEST(ElementsAreTest, DoesNotMatchWrongOrder) { + vector test_vector; + test_vector.push_back("one"); + test_vector.push_back("three"); + test_vector.push_back("two"); + + Matcher> m = + ElementsAre(StrEq("one"), StrEq("two"), StrEq("three")); + EXPECT_FALSE(m.Matches(test_vector)); +} + +TEST(ElementsAreTest, WorksForNestedContainer) { + constexpr std::array strings = {{"Hi", "world"}}; + + vector> nested; + for (const auto& s : strings) { + nested.emplace_back(s, s + strlen(s)); + } + + EXPECT_THAT(nested, ElementsAre(ElementsAre('H', Ne('e')), + ElementsAre('w', 'o', _, _, 'd'))); + EXPECT_THAT(nested, Not(ElementsAre(ElementsAre('H', 'e'), + ElementsAre('w', 'o', _, _, 'd')))); +} + +TEST(ElementsAreTest, WorksWithByRefElementMatchers) { + int a[] = {0, 1, 2}; + vector v(std::begin(a), std::end(a)); + + EXPECT_THAT(v, ElementsAre(Ref(v[0]), Ref(v[1]), Ref(v[2]))); + EXPECT_THAT(v, Not(ElementsAre(Ref(v[0]), Ref(v[1]), Ref(a[2])))); +} + +TEST(ElementsAreTest, WorksWithContainerPointerUsingPointee) { + int a[] = {0, 1, 2}; + vector v(std::begin(a), std::end(a)); + + EXPECT_THAT(&v, Pointee(ElementsAre(0, 1, _))); + EXPECT_THAT(&v, Not(Pointee(ElementsAre(0, _, 3)))); +} + +TEST(ElementsAreTest, WorksWithNativeArrayPassedByReference) { + int array[] = {0, 1, 2}; + EXPECT_THAT(array, ElementsAre(0, 1, _)); + EXPECT_THAT(array, Not(ElementsAre(1, _, _))); + EXPECT_THAT(array, Not(ElementsAre(0, _))); +} + +class NativeArrayPassedAsPointerAndSize { + public: + NativeArrayPassedAsPointerAndSize() {} + + MOCK_METHOD(void, Helper, (int* array, int size)); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NativeArrayPassedAsPointerAndSize); +}; + +TEST(ElementsAreTest, WorksWithNativeArrayPassedAsPointerAndSize) { + int array[] = {0, 1}; + ::std::tuple array_as_tuple(array, 2); + EXPECT_THAT(array_as_tuple, ElementsAre(0, 1)); + EXPECT_THAT(array_as_tuple, Not(ElementsAre(0))); + + NativeArrayPassedAsPointerAndSize helper; + EXPECT_CALL(helper, Helper(_, _)).With(ElementsAre(0, 1)); + helper.Helper(array, 2); +} + +TEST(ElementsAreTest, WorksWithTwoDimensionalNativeArray) { + const char a2[][3] = {"hi", "lo"}; + EXPECT_THAT(a2, ElementsAre(ElementsAre('h', 'i', '\0'), + ElementsAre('l', 'o', '\0'))); + EXPECT_THAT(a2, ElementsAre(StrEq("hi"), StrEq("lo"))); + EXPECT_THAT(a2, ElementsAre(Not(ElementsAre('h', 'o', '\0')), + ElementsAre('l', 'o', '\0'))); +} + +TEST(ElementsAreTest, AcceptsStringLiteral) { + std::string array[] = {"hi", "one", "two"}; + EXPECT_THAT(array, ElementsAre("hi", "one", "two")); + EXPECT_THAT(array, Not(ElementsAre("hi", "one", "too"))); +} + +// Declared here with the size unknown. Defined AFTER the following test. +extern const char kHi[]; + +TEST(ElementsAreTest, AcceptsArrayWithUnknownSize) { + // The size of kHi is not known in this test, but ElementsAre() should + // still accept it. + + std::string array1[] = {"hi"}; + EXPECT_THAT(array1, ElementsAre(kHi)); + + std::string array2[] = {"ho"}; + EXPECT_THAT(array2, Not(ElementsAre(kHi))); +} + +const char kHi[] = "hi"; + +TEST(ElementsAreTest, MakesCopyOfArguments) { + int x = 1; + int y = 2; + // This should make a copy of x and y. + ::testing::internal::ElementsAreMatcher> + polymorphic_matcher = ElementsAre(x, y); + // Changing x and y now shouldn't affect the meaning of the above matcher. + x = y = 0; + const int array1[] = {1, 2}; + EXPECT_THAT(array1, polymorphic_matcher); + const int array2[] = {0, 0}; + EXPECT_THAT(array2, Not(polymorphic_matcher)); +} + +// Tests for ElementsAreArray(). Since ElementsAreArray() shares most +// of the implementation with ElementsAre(), we don't test it as +// thoroughly here. + +TEST(ElementsAreArrayTest, CanBeCreatedWithValueArray) { + const int a[] = {1, 2, 3}; + + vector test_vector(std::begin(a), std::end(a)); + EXPECT_THAT(test_vector, ElementsAreArray(a)); + + test_vector[2] = 0; + EXPECT_THAT(test_vector, Not(ElementsAreArray(a))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithArraySize) { + std::array a = {{"one", "two", "three"}}; + + vector test_vector(std::begin(a), std::end(a)); + EXPECT_THAT(test_vector, ElementsAreArray(a.data(), a.size())); + + const char** p = a.data(); + test_vector[0] = "1"; + EXPECT_THAT(test_vector, Not(ElementsAreArray(p, a.size()))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithoutArraySize) { + const char* a[] = {"one", "two", "three"}; + + vector test_vector(std::begin(a), std::end(a)); + EXPECT_THAT(test_vector, ElementsAreArray(a)); + + test_vector[0] = "1"; + EXPECT_THAT(test_vector, Not(ElementsAreArray(a))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherArray) { + const Matcher kMatcherArray[] = {StrEq("one"), StrEq("two"), + StrEq("three")}; + + vector test_vector; + test_vector.push_back("one"); + test_vector.push_back("two"); + test_vector.push_back("three"); + EXPECT_THAT(test_vector, ElementsAreArray(kMatcherArray)); + + test_vector.push_back("three"); + EXPECT_THAT(test_vector, Not(ElementsAreArray(kMatcherArray))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithVector) { + const int a[] = {1, 2, 3}; + vector test_vector(std::begin(a), std::end(a)); + const vector expected(std::begin(a), std::end(a)); + EXPECT_THAT(test_vector, ElementsAreArray(expected)); + test_vector.push_back(4); + EXPECT_THAT(test_vector, Not(ElementsAreArray(expected))); +} + +TEST(ElementsAreArrayTest, TakesInitializerList) { + const int a[5] = {1, 2, 3, 4, 5}; + EXPECT_THAT(a, ElementsAreArray({1, 2, 3, 4, 5})); + EXPECT_THAT(a, Not(ElementsAreArray({1, 2, 3, 5, 4}))); + EXPECT_THAT(a, Not(ElementsAreArray({1, 2, 3, 4, 6}))); +} + +TEST(ElementsAreArrayTest, TakesInitializerListOfCStrings) { + const std::string a[5] = {"a", "b", "c", "d", "e"}; + EXPECT_THAT(a, ElementsAreArray({"a", "b", "c", "d", "e"})); + EXPECT_THAT(a, Not(ElementsAreArray({"a", "b", "c", "e", "d"}))); + EXPECT_THAT(a, Not(ElementsAreArray({"a", "b", "c", "d", "ef"}))); +} + +TEST(ElementsAreArrayTest, TakesInitializerListOfSameTypedMatchers) { + const int a[5] = {1, 2, 3, 4, 5}; + EXPECT_THAT(a, ElementsAreArray({Eq(1), Eq(2), Eq(3), Eq(4), Eq(5)})); + EXPECT_THAT(a, Not(ElementsAreArray({Eq(1), Eq(2), Eq(3), Eq(4), Eq(6)}))); +} + +TEST(ElementsAreArrayTest, TakesInitializerListOfDifferentTypedMatchers) { + const int a[5] = {1, 2, 3, 4, 5}; + // The compiler cannot infer the type of the initializer list if its + // elements have different types. We must explicitly specify the + // unified element type in this case. + EXPECT_THAT( + a, ElementsAreArray>({Eq(1), Ne(-2), Ge(3), Le(4), Eq(5)})); + EXPECT_THAT(a, Not(ElementsAreArray>( + {Eq(1), Ne(-2), Ge(3), Le(4), Eq(6)}))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithMatcherVector) { + const int a[] = {1, 2, 3}; + const Matcher kMatchers[] = {Eq(1), Eq(2), Eq(3)}; + vector test_vector(std::begin(a), std::end(a)); + const vector> expected(std::begin(kMatchers), + std::end(kMatchers)); + EXPECT_THAT(test_vector, ElementsAreArray(expected)); + test_vector.push_back(4); + EXPECT_THAT(test_vector, Not(ElementsAreArray(expected))); +} + +TEST(ElementsAreArrayTest, CanBeCreatedWithIteratorRange) { + const int a[] = {1, 2, 3}; + const vector test_vector(std::begin(a), std::end(a)); + const vector expected(std::begin(a), std::end(a)); + EXPECT_THAT(test_vector, ElementsAreArray(expected.begin(), expected.end())); + // Pointers are iterators, too. + EXPECT_THAT(test_vector, ElementsAreArray(std::begin(a), std::end(a))); + // The empty range of NULL pointers should also be okay. + int* const null_int = nullptr; + EXPECT_THAT(test_vector, Not(ElementsAreArray(null_int, null_int))); + EXPECT_THAT((vector()), ElementsAreArray(null_int, null_int)); +} + +// Since ElementsAre() and ElementsAreArray() share much of the +// implementation, we only do a sanity test for native arrays here. +TEST(ElementsAreArrayTest, WorksWithNativeArray) { + ::std::string a[] = {"hi", "ho"}; + ::std::string b[] = {"hi", "ho"}; + + EXPECT_THAT(a, ElementsAreArray(b)); + EXPECT_THAT(a, ElementsAreArray(b, 2)); + EXPECT_THAT(a, Not(ElementsAreArray(b, 1))); +} + +TEST(ElementsAreArrayTest, SourceLifeSpan) { + const int a[] = {1, 2, 3}; + vector test_vector(std::begin(a), std::end(a)); + vector expect(std::begin(a), std::end(a)); + ElementsAreArrayMatcher matcher_maker = + ElementsAreArray(expect.begin(), expect.end()); + EXPECT_THAT(test_vector, matcher_maker); + // Changing in place the values that initialized matcher_maker should not + // affect matcher_maker anymore. It should have made its own copy of them. + for (int& i : expect) { + i += 10; + } + EXPECT_THAT(test_vector, matcher_maker); + test_vector.push_back(3); + EXPECT_THAT(test_vector, Not(matcher_maker)); +} + +// Tests for the MATCHER*() macro family. + +// Tests that a simple MATCHER() definition works. + +MATCHER(IsEven, "") { return (arg % 2) == 0; } + +TEST(MatcherMacroTest, Works) { + const Matcher m = IsEven(); + EXPECT_TRUE(m.Matches(6)); + EXPECT_FALSE(m.Matches(7)); + + EXPECT_EQ("is even", Describe(m)); + EXPECT_EQ("not (is even)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 6)); + EXPECT_EQ("", Explain(m, 7)); +} + +// This also tests that the description string can reference 'negation'. +MATCHER(IsEven2, negation ? "is odd" : "is even") { + if ((arg % 2) == 0) { + // Verifies that we can stream to result_listener, a listener + // supplied by the MATCHER macro implicitly. + *result_listener << "OK"; + return true; + } else { + *result_listener << "% 2 == " << (arg % 2); + return false; + } +} + +// This also tests that the description string can reference matcher +// parameters. +MATCHER_P2(EqSumOf, x, y, + std::string(negation ? "doesn't equal" : "equals") + " the sum of " + + PrintToString(x) + " and " + PrintToString(y)) { + if (arg == (x + y)) { + *result_listener << "OK"; + return true; + } else { + // Verifies that we can stream to the underlying stream of + // result_listener. + if (result_listener->stream() != nullptr) { + *result_listener->stream() << "diff == " << (x + y - arg); + } + return false; + } +} + +// Tests that the matcher description can reference 'negation' and the +// matcher parameters. +TEST(MatcherMacroTest, DescriptionCanReferenceNegationAndParameters) { + const Matcher m1 = IsEven2(); + EXPECT_EQ("is even", Describe(m1)); + EXPECT_EQ("is odd", DescribeNegation(m1)); + + const Matcher m2 = EqSumOf(5, 9); + EXPECT_EQ("equals the sum of 5 and 9", Describe(m2)); + EXPECT_EQ("doesn't equal the sum of 5 and 9", DescribeNegation(m2)); +} + +// Tests explaining match result in a MATCHER* macro. +TEST(MatcherMacroTest, CanExplainMatchResult) { + const Matcher m1 = IsEven2(); + EXPECT_EQ("OK", Explain(m1, 4)); + EXPECT_EQ("% 2 == 1", Explain(m1, 5)); + + const Matcher m2 = EqSumOf(1, 2); + EXPECT_EQ("OK", Explain(m2, 3)); + EXPECT_EQ("diff == -1", Explain(m2, 4)); +} + +// Tests that the body of MATCHER() can reference the type of the +// value being matched. + +MATCHER(IsEmptyString, "") { + StaticAssertTypeEq<::std::string, arg_type>(); + return arg.empty(); +} + +MATCHER(IsEmptyStringByRef, "") { + StaticAssertTypeEq(); + return arg.empty(); +} + +TEST(MatcherMacroTest, CanReferenceArgType) { + const Matcher<::std::string> m1 = IsEmptyString(); + EXPECT_TRUE(m1.Matches("")); + + const Matcher m2 = IsEmptyStringByRef(); + EXPECT_TRUE(m2.Matches("")); +} + +// Tests that MATCHER() can be used in a namespace. + +namespace matcher_test { +MATCHER(IsOdd, "") { return (arg % 2) != 0; } +} // namespace matcher_test + +TEST(MatcherMacroTest, WorksInNamespace) { + Matcher m = matcher_test::IsOdd(); + EXPECT_FALSE(m.Matches(4)); + EXPECT_TRUE(m.Matches(5)); +} + +// Tests that Value() can be used to compose matchers. +MATCHER(IsPositiveOdd, "") { + return Value(arg, matcher_test::IsOdd()) && arg > 0; +} + +TEST(MatcherMacroTest, CanBeComposedUsingValue) { + EXPECT_THAT(3, IsPositiveOdd()); + EXPECT_THAT(4, Not(IsPositiveOdd())); + EXPECT_THAT(-1, Not(IsPositiveOdd())); +} + +// Tests that a simple MATCHER_P() definition works. + +MATCHER_P(IsGreaterThan32And, n, "") { return arg > 32 && arg > n; } + +TEST(MatcherPMacroTest, Works) { + const Matcher m = IsGreaterThan32And(5); + EXPECT_TRUE(m.Matches(36)); + EXPECT_FALSE(m.Matches(5)); + + EXPECT_EQ("is greater than 32 and 5", Describe(m)); + EXPECT_EQ("not (is greater than 32 and 5)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36)); + EXPECT_EQ("", Explain(m, 5)); +} + +// Tests that the description is calculated correctly from the matcher name. +MATCHER_P(_is_Greater_Than32and_, n, "") { return arg > 32 && arg > n; } + +TEST(MatcherPMacroTest, GeneratesCorrectDescription) { + const Matcher m = _is_Greater_Than32and_(5); + + EXPECT_EQ("is greater than 32 and 5", Describe(m)); + EXPECT_EQ("not (is greater than 32 and 5)", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36)); + EXPECT_EQ("", Explain(m, 5)); +} + +// Tests that a MATCHER_P matcher can be explicitly instantiated with +// a reference parameter type. + +class UncopyableFoo { + public: + explicit UncopyableFoo(char value) : value_(value) { (void)value_; } + + UncopyableFoo(const UncopyableFoo&) = delete; + void operator=(const UncopyableFoo&) = delete; + + private: + char value_; +}; + +MATCHER_P(ReferencesUncopyable, variable, "") { return &arg == &variable; } + +TEST(MatcherPMacroTest, WorksWhenExplicitlyInstantiatedWithReference) { + UncopyableFoo foo1('1'), foo2('2'); + const Matcher m = + ReferencesUncopyable(foo1); + + EXPECT_TRUE(m.Matches(foo1)); + EXPECT_FALSE(m.Matches(foo2)); + + // We don't want the address of the parameter printed, as most + // likely it will just annoy the user. If the address is + // interesting, the user should consider passing the parameter by + // pointer instead. + EXPECT_EQ("references uncopyable 1-byte object <31>", Describe(m)); +} + +// Tests that the body of MATCHER_Pn() can reference the parameter +// types. + +MATCHER_P3(ParamTypesAreIntLongAndChar, foo, bar, baz, "") { + StaticAssertTypeEq(); + StaticAssertTypeEq(); // NOLINT + StaticAssertTypeEq(); + return arg == 0; +} + +TEST(MatcherPnMacroTest, CanReferenceParamTypes) { + EXPECT_THAT(0, ParamTypesAreIntLongAndChar(10, 20L, 'a')); +} + +// Tests that a MATCHER_Pn matcher can be explicitly instantiated with +// reference parameter types. + +MATCHER_P2(ReferencesAnyOf, variable1, variable2, "") { + return &arg == &variable1 || &arg == &variable2; +} + +TEST(MatcherPnMacroTest, WorksWhenExplicitlyInstantiatedWithReferences) { + UncopyableFoo foo1('1'), foo2('2'), foo3('3'); + const Matcher const_m = + ReferencesAnyOf(foo1, foo2); + + EXPECT_TRUE(const_m.Matches(foo1)); + EXPECT_TRUE(const_m.Matches(foo2)); + EXPECT_FALSE(const_m.Matches(foo3)); + + const Matcher m = + ReferencesAnyOf(foo1, foo2); + + EXPECT_TRUE(m.Matches(foo1)); + EXPECT_TRUE(m.Matches(foo2)); + EXPECT_FALSE(m.Matches(foo3)); +} + +TEST(MatcherPnMacroTest, + GeneratesCorretDescriptionWhenExplicitlyInstantiatedWithReferences) { + UncopyableFoo foo1('1'), foo2('2'); + const Matcher m = + ReferencesAnyOf(foo1, foo2); + + // We don't want the addresses of the parameters printed, as most + // likely they will just annoy the user. If the addresses are + // interesting, the user should consider passing the parameters by + // pointers instead. + EXPECT_EQ("references any of (1-byte object <31>, 1-byte object <32>)", + Describe(m)); +} + +// Tests that a simple MATCHER_P2() definition works. + +MATCHER_P2(IsNotInClosedRange, low, hi, "") { return arg < low || arg > hi; } + +TEST(MatcherPnMacroTest, Works) { + const Matcher m = IsNotInClosedRange(10, 20); // NOLINT + EXPECT_TRUE(m.Matches(36L)); + EXPECT_FALSE(m.Matches(15L)); + + EXPECT_EQ("is not in closed range (10, 20)", Describe(m)); + EXPECT_EQ("not (is not in closed range (10, 20))", DescribeNegation(m)); + EXPECT_EQ("", Explain(m, 36L)); + EXPECT_EQ("", Explain(m, 15L)); +} + +// Tests that MATCHER*() definitions can be overloaded on the number +// of parameters; also tests MATCHER_Pn() where n >= 3. + +MATCHER(EqualsSumOf, "") { return arg == 0; } +MATCHER_P(EqualsSumOf, a, "") { return arg == a; } +MATCHER_P2(EqualsSumOf, a, b, "") { return arg == a + b; } +MATCHER_P3(EqualsSumOf, a, b, c, "") { return arg == a + b + c; } +MATCHER_P4(EqualsSumOf, a, b, c, d, "") { return arg == a + b + c + d; } +MATCHER_P5(EqualsSumOf, a, b, c, d, e, "") { return arg == a + b + c + d + e; } +MATCHER_P6(EqualsSumOf, a, b, c, d, e, f, "") { + return arg == a + b + c + d + e + f; +} +MATCHER_P7(EqualsSumOf, a, b, c, d, e, f, g, "") { + return arg == a + b + c + d + e + f + g; +} +MATCHER_P8(EqualsSumOf, a, b, c, d, e, f, g, h, "") { + return arg == a + b + c + d + e + f + g + h; +} +MATCHER_P9(EqualsSumOf, a, b, c, d, e, f, g, h, i, "") { + return arg == a + b + c + d + e + f + g + h + i; +} +MATCHER_P10(EqualsSumOf, a, b, c, d, e, f, g, h, i, j, "") { + return arg == a + b + c + d + e + f + g + h + i + j; +} + +TEST(MatcherPnMacroTest, CanBeOverloadedOnNumberOfParameters) { + EXPECT_THAT(0, EqualsSumOf()); + EXPECT_THAT(1, EqualsSumOf(1)); + EXPECT_THAT(12, EqualsSumOf(10, 2)); + EXPECT_THAT(123, EqualsSumOf(100, 20, 3)); + EXPECT_THAT(1234, EqualsSumOf(1000, 200, 30, 4)); + EXPECT_THAT(12345, EqualsSumOf(10000, 2000, 300, 40, 5)); + EXPECT_THAT("abcdef", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f')); + EXPECT_THAT("abcdefg", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g')); + EXPECT_THAT("abcdefgh", EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", + 'f', 'g', "h")); + EXPECT_THAT("abcdefghi", EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", + 'f', 'g', "h", 'i')); + EXPECT_THAT("abcdefghij", + EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', "h", + 'i', ::std::string("j"))); + + EXPECT_THAT(1, Not(EqualsSumOf())); + EXPECT_THAT(-1, Not(EqualsSumOf(1))); + EXPECT_THAT(-12, Not(EqualsSumOf(10, 2))); + EXPECT_THAT(-123, Not(EqualsSumOf(100, 20, 3))); + EXPECT_THAT(-1234, Not(EqualsSumOf(1000, 200, 30, 4))); + EXPECT_THAT(-12345, Not(EqualsSumOf(10000, 2000, 300, 40, 5))); + EXPECT_THAT("abcdef ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f'))); + EXPECT_THAT("abcdefg ", Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", + "e", 'f', 'g'))); + EXPECT_THAT("abcdefgh ", Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", + "e", 'f', 'g', "h"))); + EXPECT_THAT("abcdefghi ", Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", + "e", 'f', 'g', "h", 'i'))); + EXPECT_THAT("abcdefghij ", + Not(EqualsSumOf(::std::string("a"), 'b', 'c', "d", "e", 'f', 'g', + "h", 'i', ::std::string("j")))); +} + +// Tests that a MATCHER_Pn() definition can be instantiated with any +// compatible parameter types. +TEST(MatcherPnMacroTest, WorksForDifferentParameterTypes) { + EXPECT_THAT(123, EqualsSumOf(100L, 20, static_cast(3))); + EXPECT_THAT("abcd", EqualsSumOf(::std::string("a"), "b", 'c', "d")); + + EXPECT_THAT(124, Not(EqualsSumOf(100L, 20, static_cast(3)))); + EXPECT_THAT("abcde", Not(EqualsSumOf(::std::string("a"), "b", 'c', "d"))); +} + +// Tests that the matcher body can promote the parameter types. + +MATCHER_P2(EqConcat, prefix, suffix, "") { + // The following lines promote the two parameters to desired types. + std::string prefix_str(prefix); + char suffix_char = static_cast(suffix); + return arg == prefix_str + suffix_char; +} + +TEST(MatcherPnMacroTest, SimpleTypePromotion) { + Matcher no_promo = EqConcat(std::string("foo"), 't'); + Matcher promo = EqConcat("foo", static_cast('t')); + EXPECT_FALSE(no_promo.Matches("fool")); + EXPECT_FALSE(promo.Matches("fool")); + EXPECT_TRUE(no_promo.Matches("foot")); + EXPECT_TRUE(promo.Matches("foot")); +} + +// Verifies the type of a MATCHER*. + +TEST(MatcherPnMacroTest, TypesAreCorrect) { + // EqualsSumOf() must be assignable to a EqualsSumOfMatcher variable. + EqualsSumOfMatcher a0 = EqualsSumOf(); + + // EqualsSumOf(1) must be assignable to a EqualsSumOfMatcherP variable. + EqualsSumOfMatcherP a1 = EqualsSumOf(1); + + // EqualsSumOf(p1, ..., pk) must be assignable to a EqualsSumOfMatcherPk + // variable, and so on. + EqualsSumOfMatcherP2 a2 = EqualsSumOf(1, '2'); + EqualsSumOfMatcherP3 a3 = EqualsSumOf(1, 2, '3'); + EqualsSumOfMatcherP4 a4 = EqualsSumOf(1, 2, 3, '4'); + EqualsSumOfMatcherP5 a5 = + EqualsSumOf(1, 2, 3, 4, '5'); + EqualsSumOfMatcherP6 a6 = + EqualsSumOf(1, 2, 3, 4, 5, '6'); + EqualsSumOfMatcherP7 a7 = + EqualsSumOf(1, 2, 3, 4, 5, 6, '7'); + EqualsSumOfMatcherP8 a8 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, '8'); + EqualsSumOfMatcherP9 a9 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, '9'); + EqualsSumOfMatcherP10 a10 = + EqualsSumOf(1, 2, 3, 4, 5, 6, 7, 8, 9, '0'); + + // Avoid "unused variable" warnings. + (void)a0; + (void)a1; + (void)a2; + (void)a3; + (void)a4; + (void)a5; + (void)a6; + (void)a7; + (void)a8; + (void)a9; + (void)a10; +} + +// Tests that matcher-typed parameters can be used in Value() inside a +// MATCHER_Pn definition. + +// Succeeds if arg matches exactly 2 of the 3 matchers. +MATCHER_P3(TwoOf, m1, m2, m3, "") { + const int count = static_cast(Value(arg, m1)) + + static_cast(Value(arg, m2)) + + static_cast(Value(arg, m3)); + return count == 2; +} + +TEST(MatcherPnMacroTest, CanUseMatcherTypedParameterInValue) { + EXPECT_THAT(42, TwoOf(Gt(0), Lt(50), Eq(10))); + EXPECT_THAT(0, Not(TwoOf(Gt(-1), Lt(1), Eq(0)))); +} + +// Tests Contains(). + +TEST(ContainsTest, ListMatchesWhenElementIsInContainer) { + list some_list; + some_list.push_back(3); + some_list.push_back(1); + some_list.push_back(2); + EXPECT_THAT(some_list, Contains(1)); + EXPECT_THAT(some_list, Contains(Gt(2.5))); + EXPECT_THAT(some_list, Contains(Eq(2.0f))); + + list another_list; + another_list.push_back("fee"); + another_list.push_back("fie"); + another_list.push_back("foe"); + another_list.push_back("fum"); + EXPECT_THAT(another_list, Contains(std::string("fee"))); +} + +TEST(ContainsTest, ListDoesNotMatchWhenElementIsNotInContainer) { + list some_list; + some_list.push_back(3); + some_list.push_back(1); + EXPECT_THAT(some_list, Not(Contains(4))); +} + +TEST(ContainsTest, SetMatchesWhenElementIsInContainer) { + set some_set; + some_set.insert(3); + some_set.insert(1); + some_set.insert(2); + EXPECT_THAT(some_set, Contains(Eq(1.0))); + EXPECT_THAT(some_set, Contains(Eq(3.0f))); + EXPECT_THAT(some_set, Contains(2)); + + set another_set; + another_set.insert("fee"); + another_set.insert("fie"); + another_set.insert("foe"); + another_set.insert("fum"); + EXPECT_THAT(another_set, Contains(Eq(std::string("fum")))); +} + +TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { + set some_set; + some_set.insert(3); + some_set.insert(1); + EXPECT_THAT(some_set, Not(Contains(4))); + + set c_string_set; + c_string_set.insert("hello"); + EXPECT_THAT(c_string_set, Not(Contains(std::string("goodbye")))); +} + +TEST(ContainsTest, ExplainsMatchResultCorrectly) { + const int a[2] = {1, 2}; + Matcher m = Contains(2); + EXPECT_EQ("whose element #1 matches", Explain(m, a)); + + m = Contains(3); + EXPECT_EQ("", Explain(m, a)); + + m = Contains(GreaterThan(0)); + EXPECT_EQ("whose element #0 matches, which is 1 more than 0", Explain(m, a)); + + m = Contains(GreaterThan(10)); + EXPECT_EQ("", Explain(m, a)); +} + +TEST(ContainsTest, DescribesItselfCorrectly) { + Matcher> m = Contains(1); + EXPECT_EQ("contains at least one element that is equal to 1", Describe(m)); + + Matcher> m2 = Not(m); + EXPECT_EQ("doesn't contain any element that is equal to 1", Describe(m2)); +} + +TEST(ContainsTest, MapMatchesWhenElementIsInContainer) { + map my_map; + const char* bar = "a string"; + my_map[bar] = 2; + EXPECT_THAT(my_map, Contains(pair(bar, 2))); + + map another_map; + another_map["fee"] = 1; + another_map["fie"] = 2; + another_map["foe"] = 3; + another_map["fum"] = 4; + EXPECT_THAT(another_map, + Contains(pair(std::string("fee"), 1))); + EXPECT_THAT(another_map, Contains(pair("fie", 2))); +} + +TEST(ContainsTest, MapDoesNotMatchWhenElementIsNotInContainer) { + map some_map; + some_map[1] = 11; + some_map[2] = 22; + EXPECT_THAT(some_map, Not(Contains(pair(2, 23)))); +} + +TEST(ContainsTest, ArrayMatchesWhenElementIsInContainer) { + const char* string_array[] = {"fee", "fie", "foe", "fum"}; + EXPECT_THAT(string_array, Contains(Eq(std::string("fum")))); +} + +TEST(ContainsTest, ArrayDoesNotMatchWhenElementIsNotInContainer) { + int int_array[] = {1, 2, 3, 4}; + EXPECT_THAT(int_array, Not(Contains(5))); +} + +TEST(ContainsTest, AcceptsMatcher) { + const int a[] = {1, 2, 3}; + EXPECT_THAT(a, Contains(Gt(2))); + EXPECT_THAT(a, Not(Contains(Gt(4)))); +} + +TEST(ContainsTest, WorksForNativeArrayAsTuple) { + const int a[] = {1, 2}; + const int* const pointer = a; + EXPECT_THAT(std::make_tuple(pointer, 2), Contains(1)); + EXPECT_THAT(std::make_tuple(pointer, 2), Not(Contains(Gt(3)))); +} + +TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { + int a[][3] = {{1, 2, 3}, {4, 5, 6}}; + EXPECT_THAT(a, Contains(ElementsAre(4, 5, 6))); + EXPECT_THAT(a, Contains(Contains(5))); + EXPECT_THAT(a, Not(Contains(ElementsAre(3, 4, 5)))); + EXPECT_THAT(a, Contains(Not(Contains(5)))); +} + +TEST(AllOfArrayTest, BasicForms) { + // Iterator + std::vector v0{}; + std::vector v1{1}; + std::vector v2{2, 3}; + std::vector v3{4, 4, 4}; + EXPECT_THAT(0, AllOfArray(v0.begin(), v0.end())); + EXPECT_THAT(1, AllOfArray(v1.begin(), v1.end())); + EXPECT_THAT(2, Not(AllOfArray(v1.begin(), v1.end()))); + EXPECT_THAT(3, Not(AllOfArray(v2.begin(), v2.end()))); + EXPECT_THAT(4, AllOfArray(v3.begin(), v3.end())); + // Pointer + size + int ar[6] = {1, 2, 3, 4, 4, 4}; + EXPECT_THAT(0, AllOfArray(ar, 0)); + EXPECT_THAT(1, AllOfArray(ar, 1)); + EXPECT_THAT(2, Not(AllOfArray(ar, 1))); + EXPECT_THAT(3, Not(AllOfArray(ar + 1, 3))); + EXPECT_THAT(4, AllOfArray(ar + 3, 3)); + // Array + // int ar0[0]; Not usable + int ar1[1] = {1}; + int ar2[2] = {2, 3}; + int ar3[3] = {4, 4, 4}; + // EXPECT_THAT(0, Not(AllOfArray(ar0))); // Cannot work + EXPECT_THAT(1, AllOfArray(ar1)); + EXPECT_THAT(2, Not(AllOfArray(ar1))); + EXPECT_THAT(3, Not(AllOfArray(ar2))); + EXPECT_THAT(4, AllOfArray(ar3)); + // Container + EXPECT_THAT(0, AllOfArray(v0)); + EXPECT_THAT(1, AllOfArray(v1)); + EXPECT_THAT(2, Not(AllOfArray(v1))); + EXPECT_THAT(3, Not(AllOfArray(v2))); + EXPECT_THAT(4, AllOfArray(v3)); + // Initializer + EXPECT_THAT(0, AllOfArray({})); // Requires template arg. + EXPECT_THAT(1, AllOfArray({1})); + EXPECT_THAT(2, Not(AllOfArray({1}))); + EXPECT_THAT(3, Not(AllOfArray({2, 3}))); + EXPECT_THAT(4, AllOfArray({4, 4, 4})); +} + +TEST(AllOfArrayTest, Matchers) { + // vector + std::vector> matchers{Ge(1), Lt(2)}; + EXPECT_THAT(0, Not(AllOfArray(matchers))); + EXPECT_THAT(1, AllOfArray(matchers)); + EXPECT_THAT(2, Not(AllOfArray(matchers))); + // initializer_list + EXPECT_THAT(0, Not(AllOfArray({Ge(0), Ge(1)}))); + EXPECT_THAT(1, AllOfArray({Ge(0), Ge(1)})); +} + +TEST(AnyOfArrayTest, BasicForms) { + // Iterator + std::vector v0{}; + std::vector v1{1}; + std::vector v2{2, 3}; + EXPECT_THAT(0, Not(AnyOfArray(v0.begin(), v0.end()))); + EXPECT_THAT(1, AnyOfArray(v1.begin(), v1.end())); + EXPECT_THAT(2, Not(AnyOfArray(v1.begin(), v1.end()))); + EXPECT_THAT(3, AnyOfArray(v2.begin(), v2.end())); + EXPECT_THAT(4, Not(AnyOfArray(v2.begin(), v2.end()))); + // Pointer + size + int ar[3] = {1, 2, 3}; + EXPECT_THAT(0, Not(AnyOfArray(ar, 0))); + EXPECT_THAT(1, AnyOfArray(ar, 1)); + EXPECT_THAT(2, Not(AnyOfArray(ar, 1))); + EXPECT_THAT(3, AnyOfArray(ar + 1, 2)); + EXPECT_THAT(4, Not(AnyOfArray(ar + 1, 2))); + // Array + // int ar0[0]; Not usable + int ar1[1] = {1}; + int ar2[2] = {2, 3}; + // EXPECT_THAT(0, Not(AnyOfArray(ar0))); // Cannot work + EXPECT_THAT(1, AnyOfArray(ar1)); + EXPECT_THAT(2, Not(AnyOfArray(ar1))); + EXPECT_THAT(3, AnyOfArray(ar2)); + EXPECT_THAT(4, Not(AnyOfArray(ar2))); + // Container + EXPECT_THAT(0, Not(AnyOfArray(v0))); + EXPECT_THAT(1, AnyOfArray(v1)); + EXPECT_THAT(2, Not(AnyOfArray(v1))); + EXPECT_THAT(3, AnyOfArray(v2)); + EXPECT_THAT(4, Not(AnyOfArray(v2))); + // Initializer + EXPECT_THAT(0, Not(AnyOfArray({}))); // Requires template arg. + EXPECT_THAT(1, AnyOfArray({1})); + EXPECT_THAT(2, Not(AnyOfArray({1}))); + EXPECT_THAT(3, AnyOfArray({2, 3})); + EXPECT_THAT(4, Not(AnyOfArray({2, 3}))); +} + +TEST(AnyOfArrayTest, Matchers) { + // We negate test AllOfArrayTest.Matchers. + // vector + std::vector> matchers{Lt(1), Ge(2)}; + EXPECT_THAT(0, AnyOfArray(matchers)); + EXPECT_THAT(1, Not(AnyOfArray(matchers))); + EXPECT_THAT(2, AnyOfArray(matchers)); + // initializer_list + EXPECT_THAT(0, AnyOfArray({Lt(0), Lt(1)})); + EXPECT_THAT(1, Not(AllOfArray({Lt(0), Lt(1)}))); +} + +TEST(AnyOfArrayTest, ExplainsMatchResultCorrectly) { + // AnyOfArray and AllOfArry use the same underlying template-template, + // thus it is sufficient to test one here. + const std::vector v0{}; + const std::vector v1{1}; + const std::vector v2{2, 3}; + const Matcher m0 = AnyOfArray(v0); + const Matcher m1 = AnyOfArray(v1); + const Matcher m2 = AnyOfArray(v2); + EXPECT_EQ("", Explain(m0, 0)); + EXPECT_EQ("", Explain(m1, 1)); + EXPECT_EQ("", Explain(m1, 2)); + EXPECT_EQ("", Explain(m2, 3)); + EXPECT_EQ("", Explain(m2, 4)); + EXPECT_EQ("()", Describe(m0)); + EXPECT_EQ("(is equal to 1)", Describe(m1)); + EXPECT_EQ("(is equal to 2) or (is equal to 3)", Describe(m2)); + EXPECT_EQ("()", DescribeNegation(m0)); + EXPECT_EQ("(isn't equal to 1)", DescribeNegation(m1)); + EXPECT_EQ("(isn't equal to 2) and (isn't equal to 3)", DescribeNegation(m2)); + // Explain with matchers + const Matcher g1 = AnyOfArray({GreaterThan(1)}); + const Matcher g2 = AnyOfArray({GreaterThan(1), GreaterThan(2)}); + // Explains the first positiv match and all prior negative matches... + EXPECT_EQ("which is 1 less than 1", Explain(g1, 0)); + EXPECT_EQ("which is the same as 1", Explain(g1, 1)); + EXPECT_EQ("which is 1 more than 1", Explain(g1, 2)); + EXPECT_EQ("which is 1 less than 1, and which is 2 less than 2", + Explain(g2, 0)); + EXPECT_EQ("which is the same as 1, and which is 1 less than 2", + Explain(g2, 1)); + EXPECT_EQ("which is 1 more than 1", // Only the first + Explain(g2, 2)); +} + +TEST(AllOfTest, HugeMatcher) { + // Verify that using AllOf with many arguments doesn't cause + // the compiler to exceed template instantiation depth limit. + EXPECT_THAT(0, testing::AllOf(_, _, _, _, _, _, _, _, _, + testing::AllOf(_, _, _, _, _, _, _, _, _, _))); +} + +TEST(AnyOfTest, HugeMatcher) { + // Verify that using AnyOf with many arguments doesn't cause + // the compiler to exceed template instantiation depth limit. + EXPECT_THAT(0, testing::AnyOf(_, _, _, _, _, _, _, _, _, + testing::AnyOf(_, _, _, _, _, _, _, _, _, _))); +} + +namespace adl_test { + +// Verifies that the implementation of ::testing::AllOf and ::testing::AnyOf +// don't issue unqualified recursive calls. If they do, the argument dependent +// name lookup will cause AllOf/AnyOf in the 'adl_test' namespace to be found +// as a candidate and the compilation will break due to an ambiguous overload. + +// The matcher must be in the same namespace as AllOf/AnyOf to make argument +// dependent lookup find those. +MATCHER(M, "") { + (void)arg; + return true; +} + +template +bool AllOf(const T1& /*t1*/, const T2& /*t2*/) { + return true; +} + +TEST(AllOfTest, DoesNotCallAllOfUnqualified) { + EXPECT_THAT(42, + testing::AllOf(M(), M(), M(), M(), M(), M(), M(), M(), M(), M())); +} + +template +bool AnyOf(const T1&, const T2&) { + return true; +} + +TEST(AnyOfTest, DoesNotCallAnyOfUnqualified) { + EXPECT_THAT(42, + testing::AnyOf(M(), M(), M(), M(), M(), M(), M(), M(), M(), M())); +} + +} // namespace adl_test + +TEST(AllOfTest, WorksOnMoveOnlyType) { + std::unique_ptr p(new int(3)); + EXPECT_THAT(p, AllOf(Pointee(Eq(3)), Pointee(Gt(0)), Pointee(Lt(5)))); + EXPECT_THAT(p, Not(AllOf(Pointee(Eq(3)), Pointee(Gt(0)), Pointee(Lt(3))))); +} + +TEST(AnyOfTest, WorksOnMoveOnlyType) { + std::unique_ptr p(new int(3)); + EXPECT_THAT(p, AnyOf(Pointee(Eq(5)), Pointee(Lt(0)), Pointee(Lt(5)))); + EXPECT_THAT(p, Not(AnyOf(Pointee(Eq(5)), Pointee(Lt(0)), Pointee(Gt(5))))); +} + +MATCHER(IsNotNull, "") { return arg != nullptr; } + +// Verifies that a matcher defined using MATCHER() can work on +// move-only types. +TEST(MatcherMacroTest, WorksOnMoveOnlyType) { + std::unique_ptr p(new int(3)); + EXPECT_THAT(p, IsNotNull()); + EXPECT_THAT(std::unique_ptr(), Not(IsNotNull())); +} + +MATCHER_P(UniquePointee, pointee, "") { return *arg == pointee; } + +// Verifies that a matcher defined using MATCHER_P*() can work on +// move-only types. +TEST(MatcherPMacroTest, WorksOnMoveOnlyType) { + std::unique_ptr p(new int(3)); + EXPECT_THAT(p, UniquePointee(3)); + EXPECT_THAT(p, Not(UniquePointee(2))); +} + +#if GTEST_HAS_EXCEPTIONS + +// std::function is used below for compatibility with older copies of +// GCC. Normally, a raw lambda is all that is needed. + +// Test that examples from documentation compile +TEST(ThrowsTest, Examples) { + EXPECT_THAT( + std::function([]() { throw std::runtime_error("message"); }), + Throws()); + + EXPECT_THAT( + std::function([]() { throw std::runtime_error("message"); }), + ThrowsMessage(HasSubstr("message"))); +} + +TEST(ThrowsTest, DoesNotGenerateDuplicateCatchClauseWarning) { + EXPECT_THAT(std::function([]() { throw std::exception(); }), + Throws()); +} + +TEST(ThrowsTest, CallableExecutedExactlyOnce) { + size_t a = 0; + + EXPECT_THAT(std::function([&a]() { + a++; + throw 10; + }), + Throws()); + EXPECT_EQ(a, 1u); + + EXPECT_THAT(std::function([&a]() { + a++; + throw std::runtime_error("message"); + }), + Throws()); + EXPECT_EQ(a, 2u); + + EXPECT_THAT(std::function([&a]() { + a++; + throw std::runtime_error("message"); + }), + ThrowsMessage(HasSubstr("message"))); + EXPECT_EQ(a, 3u); + + EXPECT_THAT(std::function([&a]() { + a++; + throw std::runtime_error("message"); + }), + Throws( + Property(&std::runtime_error::what, HasSubstr("message")))); + EXPECT_EQ(a, 4u); +} + +TEST(ThrowsTest, Describe) { + Matcher> matcher = Throws(); + std::stringstream ss; + matcher.DescribeTo(&ss); + auto explanation = ss.str(); + EXPECT_THAT(explanation, HasSubstr("std::runtime_error")); +} + +TEST(ThrowsTest, Success) { + Matcher> matcher = Throws(); + StringMatchResultListener listener; + EXPECT_TRUE(matcher.MatchAndExplain( + []() { throw std::runtime_error("error message"); }, &listener)); + EXPECT_THAT(listener.str(), HasSubstr("std::runtime_error")); +} + +TEST(ThrowsTest, FailWrongType) { + Matcher> matcher = Throws(); + StringMatchResultListener listener; + EXPECT_FALSE(matcher.MatchAndExplain( + []() { throw std::logic_error("error message"); }, &listener)); + EXPECT_THAT(listener.str(), HasSubstr("std::logic_error")); + EXPECT_THAT(listener.str(), HasSubstr("\"error message\"")); +} + +TEST(ThrowsTest, FailWrongTypeNonStd) { + Matcher> matcher = Throws(); + StringMatchResultListener listener; + EXPECT_FALSE(matcher.MatchAndExplain([]() { throw 10; }, &listener)); + EXPECT_THAT(listener.str(), + HasSubstr("throws an exception of an unknown type")); +} + +TEST(ThrowsTest, FailNoThrow) { + Matcher> matcher = Throws(); + StringMatchResultListener listener; + EXPECT_FALSE(matcher.MatchAndExplain([]() { (void)0; }, &listener)); + EXPECT_THAT(listener.str(), HasSubstr("does not throw any exception")); +} + +class ThrowsPredicateTest + : public TestWithParam>> {}; + +TEST_P(ThrowsPredicateTest, Describe) { + Matcher> matcher = GetParam(); + std::stringstream ss; + matcher.DescribeTo(&ss); + auto explanation = ss.str(); + EXPECT_THAT(explanation, HasSubstr("std::runtime_error")); + EXPECT_THAT(explanation, HasSubstr("error message")); +} + +TEST_P(ThrowsPredicateTest, Success) { + Matcher> matcher = GetParam(); + StringMatchResultListener listener; + EXPECT_TRUE(matcher.MatchAndExplain( + []() { throw std::runtime_error("error message"); }, &listener)); + EXPECT_THAT(listener.str(), HasSubstr("std::runtime_error")); +} + +TEST_P(ThrowsPredicateTest, FailWrongType) { + Matcher> matcher = GetParam(); + StringMatchResultListener listener; + EXPECT_FALSE(matcher.MatchAndExplain( + []() { throw std::logic_error("error message"); }, &listener)); + EXPECT_THAT(listener.str(), HasSubstr("std::logic_error")); + EXPECT_THAT(listener.str(), HasSubstr("\"error message\"")); +} + +TEST_P(ThrowsPredicateTest, FailWrongTypeNonStd) { + Matcher> matcher = GetParam(); + StringMatchResultListener listener; + EXPECT_FALSE(matcher.MatchAndExplain([]() { throw 10; }, &listener)); + EXPECT_THAT(listener.str(), + HasSubstr("throws an exception of an unknown type")); +} + +TEST_P(ThrowsPredicateTest, FailWrongMessage) { + Matcher> matcher = GetParam(); + StringMatchResultListener listener; + EXPECT_FALSE(matcher.MatchAndExplain( + []() { throw std::runtime_error("wrong message"); }, &listener)); + EXPECT_THAT(listener.str(), HasSubstr("std::runtime_error")); + EXPECT_THAT(listener.str(), Not(HasSubstr("wrong message"))); +} + +TEST_P(ThrowsPredicateTest, FailNoThrow) { + Matcher> matcher = GetParam(); + StringMatchResultListener listener; + EXPECT_FALSE(matcher.MatchAndExplain([]() {}, &listener)); + EXPECT_THAT(listener.str(), HasSubstr("does not throw any exception")); +} + +INSTANTIATE_TEST_SUITE_P( + AllMessagePredicates, ThrowsPredicateTest, + Values(Matcher>( + ThrowsMessage(HasSubstr("error message"))))); + +// Tests that Throws(Matcher{}) compiles even when E2 != const E1&. +TEST(ThrowsPredicateCompilesTest, ExceptionMatcherAcceptsBroadType) { + { + Matcher> matcher = + ThrowsMessage(HasSubstr("error message")); + EXPECT_TRUE( + matcher.Matches([]() { throw std::runtime_error("error message"); })); + EXPECT_FALSE( + matcher.Matches([]() { throw std::runtime_error("wrong message"); })); + } + + { + Matcher inner = Eq(10); + Matcher> matcher = Throws(inner); + EXPECT_TRUE(matcher.Matches([]() { throw(uint32_t) 10; })); + EXPECT_FALSE(matcher.Matches([]() { throw(uint32_t) 11; })); + } +} + +// Tests that ThrowsMessage("message") is equivalent +// to ThrowsMessage(Eq("message")). +TEST(ThrowsPredicateCompilesTest, MessageMatcherAcceptsNonMatcher) { + Matcher> matcher = + ThrowsMessage("error message"); + EXPECT_TRUE( + matcher.Matches([]() { throw std::runtime_error("error message"); })); + EXPECT_FALSE(matcher.Matches( + []() { throw std::runtime_error("wrong error message"); })); +} + +#endif // GTEST_HAS_EXCEPTIONS + } // namespace } // namespace gmock_matchers_test } // namespace testing diff --git a/googlemock/test/gmock-more-actions_test.cc b/googlemock/test/gmock-more-actions_test.cc index 97ec5cf08f..4bcb5df6bb 100644 --- a/googlemock/test/gmock-more-actions_test.cc +++ b/googlemock/test/gmock-more-actions_test.cc @@ -27,18 +27,18 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Google Mock - a framework for writing C++ mock classes. // -// This file tests the built-in actions in gmock-more-actions.h. - -#include "gmock/gmock-more-actions.h" +// This file tests the built-in actions in gmock-actions.h. #include #include #include #include + +#include "gmock/gmock-actions.h" #include "gmock/gmock.h" +#include "gtest/gtest-spi.h" #include "gtest/gtest.h" namespace testing { @@ -604,6 +604,33 @@ TEST(ThrowActionTest, ThrowsGivenExceptionInNullaryFunction) { EXPECT_THROW(a.Perform(std::make_tuple()), MyException); } +class Object { + public: + virtual ~Object() {} + virtual void Func() {} +}; + +class MockObject : public Object { + public: + ~MockObject() override {} + MOCK_METHOD(void, Func, (), (override)); +}; + +TEST(ThrowActionTest, Times0) { + EXPECT_NONFATAL_FAILURE( + [] { + try { + MockObject m; + ON_CALL(m, Func()).WillByDefault([] { throw "something"; }); + EXPECT_CALL(m, Func()).Times(0); + m.Func(); + } catch (...) { + // Exception is caught but Times(0) still triggers a failure. + } + }(), + ""); +} + #endif // GTEST_HAS_EXCEPTIONS // Tests that SetArrayArgument(first, last) sets the elements of the array diff --git a/googlemock/test/gmock_all_test.cc b/googlemock/test/gmock_all_test.cc index c53d0965f6..6187d4ad12 100644 --- a/googlemock/test/gmock_all_test.cc +++ b/googlemock/test/gmock_all_test.cc @@ -38,7 +38,6 @@ #include "test/gmock-actions_test.cc" #include "test/gmock-cardinalities_test.cc" #include "test/gmock-generated-actions_test.cc" -#include "test/gmock-generated-matchers_test.cc" #include "test/gmock-internal-utils_test.cc" #include "test/gmock-matchers_test.cc" #include "test/gmock-more-actions_test.cc" diff --git a/googlemock/test/gmock_output_test_golden.txt b/googlemock/test/gmock_output_test_golden.txt index 4c90b41a3a..755e9334a7 100644 --- a/googlemock/test/gmock_output_test_golden.txt +++ b/googlemock/test/gmock_output_test_golden.txt @@ -314,4 +314,4 @@ Expected: is pair (is >= 48, true) FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#. FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#. FILE:#: ERROR: this mock object should be deleted but never is. Its address is @0x#. -ERROR: 3 leaked mock objects found at program exit. Expectations on a mock object is verified when the object is destructed. Leaking a mock means that its expectations aren't verified, which is usually a test bug. If you really intend to leak a mock, you can suppress this error using testing::Mock::AllowLeak(mock_object), or you may use a fake or stub instead of a mock. +ERROR: 3 leaked mock objects found at program exit. Expectations on a mock object are verified when the object is destructed. Leaking a mock means that its expectations aren't verified, which is usually a test bug. If you really intend to leak a mock, you can suppress this error using testing::Mock::AllowLeak(mock_object), or you may use a fake or stub instead of a mock. diff --git a/googletest/cmake/internal_utils.cmake b/googletest/cmake/internal_utils.cmake index 2f70f0b084..b3e8b8190e 100644 --- a/googletest/cmake/internal_utils.cmake +++ b/googletest/cmake/internal_utils.cmake @@ -188,6 +188,10 @@ function(cxx_library_with_type name type cxx_flags) endif() target_link_libraries(${name} PUBLIC ${threads_spec}) endif() + + if (NOT "${CMAKE_VERSION}" VERSION_LESS "3.8") + target_compile_features(${name} PUBLIC cxx_std_11) + endif() endfunction() ######################################################################## diff --git a/googletest/docs/advanced.md b/googletest/docs/advanced.md index 60c1a2b0b5..755e461ed6 100644 --- a/googletest/docs/advanced.md +++ b/googletest/docs/advanced.md @@ -2,6 +2,8 @@ + + ## Introduction Now that you have read the [googletest Primer](primer.md) and learned how to @@ -187,11 +189,11 @@ write a predicate function that returns `AssertionResult` instead of `bool`. For example, if you define `IsEven()` as: ```c++ -::testing::AssertionResult IsEven(int n) { +testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) - return ::testing::AssertionSuccess(); + return testing::AssertionSuccess(); else - return ::testing::AssertionFailure() << n << " is odd"; + return testing::AssertionFailure() << n << " is odd"; } ``` @@ -225,11 +227,11 @@ are fine with making the predicate slower in the success case, you can supply a success message: ```c++ -::testing::AssertionResult IsEven(int n) { +testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) - return ::testing::AssertionSuccess() << n << " is even"; + return testing::AssertionSuccess() << n << " is even"; else - return ::testing::AssertionFailure() << n << " is odd"; + return testing::AssertionFailure() << n << " is odd"; } ``` @@ -260,14 +262,14 @@ a predicate, `(ASSERT|EXPECT)_PRED_FORMAT*` take a *predicate-formatter* (`pred_formatn`), which is a function or functor with the signature: ```c++ -::testing::AssertionResult PredicateFormattern(const char* expr1, - const char* expr2, - ... - const char* exprn, - T1 val1, - T2 val2, - ... - Tn valn); +testing::AssertionResult PredicateFormattern(const char* expr1, + const char* expr2, + ... + const char* exprn, + T1 val1, + T2 val2, + ... + Tn valn); ``` where `val1`, `val2`, ..., and `valn` are the values of the predicate arguments, @@ -285,13 +287,13 @@ used with `EXPECT_PRED2()`: int SmallestPrimeCommonDivisor(int m, int n) { ... } // A predicate-formatter for asserting that two integers are mutually prime. -::testing::AssertionResult AssertMutuallyPrime(const char* m_expr, - const char* n_expr, - int m, - int n) { - if (MutuallyPrime(m, n)) return ::testing::AssertionSuccess(); +testing::AssertionResult AssertMutuallyPrime(const char* m_expr, + const char* n_expr, + int m, + int n) { + if (MutuallyPrime(m, n)) return testing::AssertionSuccess(); - return ::testing::AssertionFailure() << m_expr << " and " << n_expr + return testing::AssertionFailure() << m_expr << " and " << n_expr << " (" << m << " and " << n << ") are not mutually prime, " << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); } @@ -360,8 +362,8 @@ that can be used in predicate assertion macros (e.g. `EXPECT_PRED_FORMAT2`, etc). ```c++ -EXPECT_PRED_FORMAT2(::testing::FloatLE, val1, val2); -EXPECT_PRED_FORMAT2(::testing::DoubleLE, val1, val2); +EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2); +EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2); ``` Verifies that `val1` is less than, or almost equal to, `val2`. You can replace @@ -369,9 +371,11 @@ Verifies that `val1` is less than, or almost equal to, `val2`. You can replace ### Asserting Using gMock Matchers -[gMock](../../googlemock) comes with a library of matchers for validating -arguments passed to mock objects. A gMock *matcher* is basically a predicate -that knows how to describe itself. It can be used in these assertion macros: +[gMock](../../googlemock) comes with +[a library of matchers](../../googlemock/docs/cheat_sheet.md#MatcherList) for +validating arguments passed to mock objects. A gMock *matcher* is basically a +predicate that knows how to describe itself. It can be used in these assertion +macros: @@ -429,7 +433,7 @@ its DOM tree matches an ```c++ // Currently still in //template/prototemplate/testing:xpath_matcher #include "template/prototemplate/testing/xpath_matcher.h" -using prototemplate::testing::MatchesXPath; +using ::prototemplate::testing::MatchesXPath; EXPECT_THAT(html_string, MatchesXPath("//a[text()='click here']")); ``` @@ -476,7 +480,7 @@ instantiated. For example, given: ```c++ template class Foo { public: - void Bar() { ::testing::StaticAssertTypeEq(); } + void Bar() { testing::StaticAssertTypeEq(); } }; ``` @@ -524,8 +528,8 @@ a `SetUp`/`TearDown` function; see [constructor/destructor vs. `SetUp`/`TearDown`](faq.md#CtorVsSetUp) WARNING: A fatal assertion in a helper function (private void-returning method) -called from a constructor or destructor does not does not terminate the current -test, as your intuition might suggest: it merely returns from the constructor or +called from a constructor or destructor does not terminate the current test, as +your intuition might suggest: it merely returns from the constructor or destructor early, possibly leaving your object in a partially-constructed or partially-destructed state! You almost certainly want to `abort` or use `SetUp`/`TearDown` instead. @@ -605,7 +609,7 @@ call `::testing::PrintToString(x)`, which returns an `std::string`: vector > bar_ints = GetBarIntVector(); EXPECT_TRUE(IsCorrectBarIntVector(bar_ints)) - << "bar_ints = " << ::testing::PrintToString(bar_ints); + << "bar_ints = " << testing::PrintToString(bar_ints); ``` ## Death Tests @@ -674,7 +678,7 @@ This expression is `true` if the program exited normally with the given exit code. ```c++ -::testing::KilledBySignal(signal_number) // Not available on Windows. +testing::KilledBySignal(signal_number) // Not available on Windows. ``` This expression is `true` if the program was killed by the given signal. @@ -707,11 +711,11 @@ TEST(MyDeathTest, Foo) { } TEST(MyDeathTest, NormalExit) { - EXPECT_EXIT(NormalExit(), ::testing::ExitedWithCode(0), "Success"); + EXPECT_EXIT(NormalExit(), testing::ExitedWithCode(0), "Success"); } TEST(MyDeathTest, KillMyself) { - EXPECT_EXIT(KillMyself(), ::testing::KilledBySignal(SIGKILL), + EXPECT_EXIT(KillMyself(), testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal"); } ``` @@ -738,7 +742,7 @@ If a test fixture class is shared by normal tests and death tests, you can use duplicating its code: ```c++ -class FooTest : public ::testing::Test { ... }; +class FooTest : public testing::Test { ... }; using FooDeathTest = FooTest; @@ -798,7 +802,7 @@ limited syntax only. Under the hood, `ASSERT_EXIT()` spawns a new process and executes the death test statement in that process. The details of how precisely that happens depend on -the platform and the variable ::testing::GTEST_FLAG(death_test_style) (which is +the platform and the variable `::testing::GTEST_FLAG(death_test_style)` (which is initialized from the command-line flag `--gtest_death_test_style`). * On POSIX systems, `fork()` (or `clone()` on Linux) is used to spawn the @@ -863,13 +867,13 @@ restored afterwards, so you need not do that yourself. For example: ```c++ int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - ::testing::FLAGS_gtest_death_test_style = "fast"; + testing::InitGoogleTest(&argc, argv); + testing::FLAGS_gtest_death_test_style = "fast"; return RUN_ALL_TESTS(); } TEST(MyDeathTest, TestOne) { - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + testing::FLAGS_gtest_death_test_style = "threadsafe"; // This test is run in the "threadsafe" style: ASSERT_DEATH(ThisShouldDie(), ""); } @@ -909,6 +913,12 @@ handlers registered with `pthread_atfork(3)`. ## Using Assertions in Sub-routines +Note: If you want to put a series of test assertions in a subroutine to check +for a complex condition, consider using +[a custom GMock matcher](../../googlemock/docs/cook_book.md#NewMatchers) +instead. This lets you provide a more readable error message in case of failure +and avoid all of the issues described below. + ### Adding Traces to Assertions If a test sub-routine is called from several places, when an assertion inside it @@ -1100,7 +1110,7 @@ If `HasFatalFailure()` is used outside of `TEST()` , `TEST_F()` , or a test fixture, you must add the `::testing::Test::` prefix, as in: ```c++ -if (::testing::Test::HasFatalFailure()) return; +if (testing::Test::HasFatalFailure()) return; ``` Similarly, `HasNonfatalFailure()` returns `true` if the current test has at @@ -1179,7 +1189,7 @@ state to its original value before passing control to the next test. Here's an example of per-test-suite set-up and tear-down: ```c++ -class FooTest : public ::testing::Test { +class FooTest : public testing::Test { protected: // Per-test-suite set-up. // Called before the first test in this test suite. @@ -1230,7 +1240,7 @@ First, you subclass the `::testing::Environment` class to define a test environment, which knows how to set-up and tear-down: ```c++ -class Environment : public ::testing::Environment { +class Environment : public testing::Environment { public: ~Environment() override {} @@ -1268,8 +1278,8 @@ probably in `main()`. If you use `gtest_main`, you need to call this before variable like this: ```c++ -::testing::Environment* const foo_env = - ::testing::AddGlobalTestEnvironment(new FooEnvironment); +testing::Environment* const foo_env = + testing::AddGlobalTestEnvironment(new FooEnvironment); ``` However, we strongly recommend you to write your own `main()` and call @@ -1375,15 +1385,11 @@ INSTANTIATE_TEST_SUITE_P(InstantiationName, NOTE: The code above must be placed at global or namespace scope, not at function scope. -NOTE: Don't forget this step! If you do your test will silently pass, but none -of its suites will ever run! - -There is work in progress to make omitting `INSTANTIATE_TEST_SUITE_P` show up -under the `GoogleTestVerification` test suite and to then make that an error. -If you have a test suite where that omission is not an error, for example it is -in a library that may be linked in for other reason or where the list of test -cases is dynamic and may be empty, then this check can be suppressed by tagging -the test suite: +Per default, every `TEST_P` without a corresponding `INSTANTIATE_TEST_SUITE_P` +causes a failing test in test suite `GoogleTestVerification`. If you have a test +suite where that omission is not an error, for example it is in a library that +may be linked in for other reason or where the list of test cases is dynamic and +may be empty, then this check can be suppressed by tagging the test suite: ```c++ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FooTest); @@ -1490,7 +1496,7 @@ for conciseness: ```c++ enum class MyType { MY_FOO = 0, MY_BAR = 1 }; -class MyTestSuite : public testing::TestWithParam> { +class MyTestSuite : public testing::TestWithParam> { }; INSTANTIATE_TEST_SUITE_P( @@ -1499,7 +1505,7 @@ INSTANTIATE_TEST_SUITE_P( testing::Values(MyType::VALUE_0, MyType::VALUE_1), testing::ValuesIn("", "")), [](const testing::TestParamInfo& info) { - string name = absl::StrCat( + std::string name = absl::StrCat( std::get<0>(info.param) == MY_FOO ? "Foo" : "Bar", "_", std::get<1>(info.param)); absl::c_replace_if(name, [](char c) { return !std::isalnum(c); }, '_'); @@ -1529,10 +1535,10 @@ Remember to derive it from `::testing::Test`: ```c++ template -class FooTest : public ::testing::Test { +class FooTest : public testing::Test { public: ... - typedef std::list List; + using List = std::list; static T shared_; T value_; }; @@ -1597,7 +1603,7 @@ First, define a fixture class template, as we did with typed tests: ```c++ template -class FooTest : public ::testing::Test { +class FooTest : public testing::Test { ... }; ``` @@ -1636,7 +1642,7 @@ put the above code in a header file, you can `#include` it in multiple C++ source files and instantiate it multiple times. ```c++ -typedef ::testing::Types MyTypes; +using MyTypes = ::testing::Types; INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); ``` @@ -1755,7 +1761,7 @@ To test them, we use the following special techniques: ```c++ namespace my_namespace { - class FooTest : public ::testing::Test { + class FooTest : public testing::Test { protected: ... }; @@ -1850,7 +1856,7 @@ undefined. Use case example: ```c++ -class MyFixture : public ::testing::Test { +class MyFixture : public testing::Test { public: // All of these optional, just like in regular macro usage. static void SetUpTestSuite() { ... } @@ -1870,7 +1876,7 @@ class MyTest : public MyFixture { void RegisterMyTests(const std::vector& values) { for (int v : values) { - ::testing::RegisterTest( + testing::RegisterTest( "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, std::to_string(v).c_str(), __FILE__, __LINE__, @@ -1915,8 +1921,8 @@ To obtain a `TestInfo` object for the currently running test, call ```c++ // Gets information about the currently running test. // Do NOT delete the returned object - it's managed by the UnitTest class. - const ::testing::TestInfo* const test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); + const testing::TestInfo* const test_info = + testing::UnitTest::GetInstance()->current_test_info(); printf("We are in test %s of test suite %s.\n", test_info->name(), @@ -1962,15 +1968,15 @@ interesting information about the event and the test program's state. Here's an example: ```c++ - class MinimalistPrinter : public ::testing::EmptyTestEventListener { + class MinimalistPrinter : public testing::EmptyTestEventListener { // Called before a test starts. - virtual void OnTestStart(const ::testing::TestInfo& test_info) { + virtual void OnTestStart(const testing::TestInfo& test_info) { printf("*** Test %s.%s starting.\n", test_info.test_suite_name(), test_info.name()); } // Called after a failed assertion or a SUCCESS(). - virtual void OnTestPartResult(const ::testing::TestPartResult& test_part_result) { + virtual void OnTestPartResult(const testing::TestPartResult& test_part_result) { printf("%s in %s:%d\n%s\n", test_part_result.failed() ? "*** Failure" : "Success", test_part_result.file_name(), @@ -1979,7 +1985,7 @@ Here's an example: } // Called after a test ends. - virtual void OnTestEnd(const ::testing::TestInfo& test_info) { + virtual void OnTestEnd(const testing::TestInfo& test_info) { printf("*** Test %s.%s ending.\n", test_info.test_suite_name(), test_info.name()); } @@ -1995,10 +2001,10 @@ the "s" at the end of the name) in your `main()` function, before calling ```c++ int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); + testing::InitGoogleTest(&argc, argv); // Gets hold of the event listener list. - ::testing::TestEventListeners& listeners = - ::testing::UnitTest::GetInstance()->listeners(); + testing::TestEventListeners& listeners = + testing::UnitTest::GetInstance()->listeners(); // Adds a listener to the end. googletest takes the ownership. listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); @@ -2143,7 +2149,7 @@ will still be compiled: // Tests that Foo does Abc. TEST(FooTest, DISABLED_DoesAbc) { ... } -class DISABLED_BarTest : public ::testing::Test { ... }; +class DISABLED_BarTest : public testing::Test { ... }; // Tests that Bar does Xyz. TEST_F(DISABLED_BarTest, DoesXyz) { ... } diff --git a/googletest/docs/faq.md b/googletest/docs/faq.md index 05ecdd7d8d..3ece95bc04 100644 --- a/googletest/docs/faq.md +++ b/googletest/docs/faq.md @@ -2,8 +2,14 @@ + + ## Why should test suite names and test names not contain underscore? +Note: Googletest reserves underscore (`_`) for special purpose keywords, such as +[the `DISABLED_` prefix](advanced.md#temporarily-disabling-tests), in addition +to the following rationale. + Underscore (`_`) is special, as C++ reserves the following to be used by the compiler and the standard library: @@ -295,7 +301,7 @@ program from the beginning in the child process. Therefore make sure your program can run side-by-side with itself and is deterministic. In the end, this boils down to good concurrent programming. You have to make -sure that there is no race conditions or dead locks in your program. No silver +sure that there are no race conditions or deadlocks in your program. No silver bullet - sorry! ## Should I use the constructor/destructor of the test fixture or SetUp()/TearDown()? {#CtorVsSetUp} @@ -401,7 +407,7 @@ you can use it in a predicate assertion like this: ASSERT_PRED1(IsNegative, -5); ``` -Things are more interesting if your template has more than one parameters. The +Things are more interesting if your template has more than one parameter. The following won't compile: ```c++ @@ -555,7 +561,7 @@ TEST(MyDeathTest, ComplexExpression) { "(Func1|Method) failed"); } -// Death assertions can be used any where in a function. In +// Death assertions can be used anywhere in a function. In // particular, they can be inside a loop. TEST(MyDeathTest, InsideLoop) { // Verifies that Foo(0), Foo(1), ..., and Foo(4) all die. @@ -597,7 +603,7 @@ However, there are cases where you have to define your own: ## Why does ASSERT_DEATH complain about previous threads that were already joined? With the Linux pthread library, there is no turning back once you cross the line -from single thread to multiple threads. The first time you create a thread, a +from a single thread to multiple threads. The first time you create a thread, a manager thread is created in addition, so you get 3, not 2, threads. Later when the thread you create joins the main thread, the thread count decrements by 1, but the manager thread will never be killed, so you still have 2 threads, which @@ -612,7 +618,7 @@ runs on, you shouldn't depend on this. googletest does not interleave tests from different test suites. That is, it runs all tests in one test suite first, and then runs all tests in the next test suite, and so on. googletest does this because it needs to set up a test suite -before the first test in it is run, and tear it down afterwords. Splitting up +before the first test in it is run, and tear it down afterwards. Splitting up the test case would require multiple set-up and tear-down processes, which is inefficient and makes the semantics unclean. diff --git a/googletest/docs/pkgconfig.md b/googletest/docs/pkgconfig.md index b9bef3fde5..aed4ad4544 100644 --- a/googletest/docs/pkgconfig.md +++ b/googletest/docs/pkgconfig.md @@ -1,5 +1,7 @@ ## Using GoogleTest from various build systems + + GoogleTest comes with pkg-config files that can be used to determine all necessary flags for compiling and linking to GoogleTest (and GoogleMock). Pkg-config is a standardised plain-text format containing diff --git a/googletest/docs/primer.md b/googletest/docs/primer.md index 2f459fd7fd..ed44369ab3 100644 --- a/googletest/docs/primer.md +++ b/googletest/docs/primer.md @@ -1,5 +1,7 @@ # Googletest Primer + + ## Introduction: Why googletest? *googletest* helps you write better C++ tests. diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index f24512a9f2..f697e2f0d2 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -192,51 +192,43 @@ struct PointerPrinter { } }; -namespace internal_stream { +namespace internal_stream_operator_without_lexical_name_lookup { -struct Sentinel; -template -Sentinel* operator<<(::std::basic_ostream& os, const T& x); - -// Check if the user has a user-defined operator<< for their type. -// -// We put this in its own namespace to inject a custom operator<< that allows us -// to probe the type's operator. -// -// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If -// we define it to take an std::ostream instead, we'll get an -// "ambiguous overloads" compiler error when trying to print a type -// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether -// operator<<(std::ostream&, const T&) or -// operator<<(std::basic_stream, const Foo&) is more -// specific. -template -constexpr bool UseStreamOperator() { - return !std::is_same() - << std::declval()), - Sentinel*>::value; -} - -} // namespace internal_stream +// The presence of an operator<< here will terminate lexical scope lookup +// straight away (even though it cannot be a match because of its argument +// types). Thus, the two operator<< calls in StreamPrinter will find only ADL +// candidates. +struct LookupBlocker {}; +void operator<<(LookupBlocker, LookupBlocker); struct StreamPrinter { - template ()>::type> + template ::value>::type, + // Only accept types for which we can find a streaming operator via + // ADL (possibly involving implicit conversions). + typename = decltype(std::declval() + << std::declval())> static void PrintValue(const T& value, ::std::ostream* os) { + // Call streaming operator found by ADL, possibly with implicit conversions + // of the arguments. *os << value; } }; +} // namespace internal_stream_operator_without_lexical_name_lookup + struct ProtobufPrinter { // We print a protobuf using its ShortDebugString() when the string // doesn't exceed this many characters; otherwise we print it using // DebugString() for better readability. static const size_t kProtobufOneLinerMaxLength = 50; - template ::value>::type> + template ::value>::type> static void PrintValue(const T& value, ::std::ostream* os) { std::string pretty_str = value.ShortDebugString(); if (pretty_str.length() > kProtobufOneLinerMaxLength) { @@ -307,7 +299,8 @@ template void PrintWithFallback(const T& value, ::std::ostream* os) { using Printer = typename FindFirstPrinter< T, void, ContainerPrinter, FunctionPointerPrinter, PointerPrinter, - StreamPrinter, ProtobufPrinter, ConvertibleToIntegerPrinter, + internal_stream_operator_without_lexical_name_lookup::StreamPrinter, + ProtobufPrinter, ConvertibleToIntegerPrinter, ConvertibleToStringViewPrinter, FallbackPrinter>::type; Printer::PrintValue(value, os); } diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index a0942b49a2..b3d40416aa 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -434,7 +434,8 @@ class GTEST_API_ Test { // class. static void TearDownTestSuite() {} - // Legacy API is deprecated but still available + // Legacy API is deprecated but still available. Use SetUpTestSuite and + // TearDownTestSuite instead. #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ static void TearDownTestCase() {} static void SetUpTestCase() {} diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 028f21eb54..d990c0f67b 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -287,7 +287,7 @@ class FloatingPoint { // // See the following article for more details on ULP: // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ - static const size_t kMaxUlps = 4; + static const uint32_t kMaxUlps = 4; // Constructs a FloatingPoint from a raw floating-point number. // @@ -520,6 +520,7 @@ struct SuiteApiResolver : T { static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename, int line_num) { +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ SetUpTearDownSuiteFuncType test_case_fp = GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase); SetUpTearDownSuiteFuncType test_suite_fp = @@ -531,10 +532,16 @@ struct SuiteApiResolver : T { << filename << ":" << line_num; return test_case_fp != nullptr ? test_case_fp : test_suite_fp; +#else + (void)(filename); + (void)(line_num); + return &T::SetUpTestSuite; +#endif } static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename, int line_num) { +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ SetUpTearDownSuiteFuncType test_case_fp = GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase); SetUpTearDownSuiteFuncType test_suite_fp = @@ -546,6 +553,11 @@ struct SuiteApiResolver : T { << filename << ":" << line_num; return test_case_fp != nullptr ? test_case_fp : test_suite_fp; +#else + (void)(filename); + (void)(line_num); + return &T::TearDownTestSuite; +#endif } }; @@ -880,11 +892,34 @@ class GTEST_API_ Random { #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ typename std::remove_const::type>::type -// IsAProtocolMessage::value is a compile-time bool constant that's -// true if and only if T is type proto2::MessageLite or a subclass of it. +// HasDebugStringAndShortDebugString::value is a compile-time bool constant +// that's true if and only if T has methods DebugString() and ShortDebugString() +// that return std::string. template -struct IsAProtocolMessage - : public std::is_convertible {}; +class HasDebugStringAndShortDebugString { + private: + template + static constexpr auto CheckDebugString(C*) -> typename std::is_same< + std::string, decltype(std::declval().DebugString())>::type; + template + static constexpr std::false_type CheckDebugString(...); + + template + static constexpr auto CheckShortDebugString(C*) -> typename std::is_same< + std::string, decltype(std::declval().ShortDebugString())>::type; + template + static constexpr std::false_type CheckShortDebugString(...); + + using HasDebugStringType = decltype(CheckDebugString(nullptr)); + using HasShortDebugStringType = decltype(CheckShortDebugString(nullptr)); + + public: + static constexpr bool value = + HasDebugStringType::value && HasShortDebugStringType::value; +}; + +template +constexpr bool HasDebugStringAndShortDebugString::value; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest @@ -1143,12 +1178,18 @@ struct DoubleSequence, sizeofT> { // Backport of std::make_index_sequence. // It uses O(ln(N)) instantiation depth. template -struct MakeIndexSequence - : DoubleSequence::type, +struct MakeIndexSequenceImpl + : DoubleSequence::type, N / 2>::type {}; template <> -struct MakeIndexSequence<0> : IndexSequence<> {}; +struct MakeIndexSequenceImpl<0> : IndexSequence<> {}; + +template +using MakeIndexSequence = typename MakeIndexSequenceImpl::type; + +template +using IndexSequenceFor = typename MakeIndexSequence::type; template struct Ignore { @@ -1174,6 +1215,8 @@ struct ElemFromList { static_cast(nullptr)...)); }; +struct FlatTupleConstructTag {}; + template class FlatTuple; @@ -1184,7 +1227,9 @@ template struct FlatTupleElemBase, I> { using value_type = typename ElemFromList::type; FlatTupleElemBase() = default; - explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} + template + explicit FlatTupleElemBase(FlatTupleConstructTag, Arg&& t) + : value(std::forward(t)) {} value_type value; }; @@ -1196,8 +1241,30 @@ struct FlatTupleBase, IndexSequence> : FlatTupleElemBase, Idx>... { using Indices = IndexSequence; FlatTupleBase() = default; - explicit FlatTupleBase(T... t) - : FlatTupleElemBase, Idx>(std::move(t))... {} + template + explicit FlatTupleBase(FlatTupleConstructTag, Args&&... args) + : FlatTupleElemBase, Idx>(FlatTupleConstructTag{}, + std::forward(args))... {} + + template + const typename ElemFromList::type& Get() const { + return FlatTupleElemBase, I>::value; + } + + template + typename ElemFromList::type& Get() { + return FlatTupleElemBase, I>::value; + } + + template + auto Apply(F&& f) -> decltype(std::forward(f)(this->Get()...)) { + return std::forward(f)(Get()...); + } + + template + auto Apply(F&& f) const -> decltype(std::forward(f)(this->Get()...)) { + return std::forward(f)(Get()...); + } }; // Analog to std::tuple but with different tradeoffs. @@ -1218,17 +1285,17 @@ class FlatTuple public: FlatTuple() = default; - explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} - - template - const typename ElemFromList::type& Get() const { - return static_cast*>(this)->value; - } - - template - typename ElemFromList::type& Get() { - return static_cast*>(this)->value; - } + template ::type...)>::value && + (sizeof...(T) >= 1)>::type> + explicit FlatTuple(Args&&... args) + : FlatTuple::FlatTupleBase(FlatTupleConstructTag{}, + std::forward(args)...) {} + + using FlatTuple::FlatTupleBase::Apply; + using FlatTuple::FlatTupleBase::Get; }; // Utility functions to be called with static_assert to induce deprecation @@ -1261,6 +1328,22 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } } // namespace internal } // namespace testing +namespace std { +// Some standard library implementations use `struct tuple_size` and some use +// `class tuple_size`. Clang warns about the mismatch. +// https://reviews.llvm.org/D55466 +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +struct tuple_size> + : std::integral_constant {}; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} // namespace std + #define GTEST_MESSAGE_AT_(file, line, message, result_type) \ ::testing::internal::AssertHelper(result_type, file, line, message) \ = ::testing::Message() @@ -1291,41 +1374,90 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } } else /* NOLINT */ \ static_assert(true, "") // User must have a semicolon after expansion. -#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::ConstCharPtr gtest_msg = "") { \ - bool gtest_caught_expected = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (expected_exception const&) { \ - gtest_caught_expected = true; \ - } \ - catch (...) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws a different type."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - if (!gtest_caught_expected) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws nothing."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg.value) +#if GTEST_HAS_EXCEPTIONS + +namespace testing { +namespace internal { + +class NeverThrown { + public: + const char* what() const noexcept { + return "this exception should never be thrown"; + } +}; + +} // namespace internal +} // namespace testing + +#if GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) ::testing::internal::GetTypeName(typeid(e)) + +#else // GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) \ + std::string { "an std::exception-derived error" } + +#endif // GTEST_HAS_RTTI + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (typename std::conditional< \ + std::is_same::type>::type, \ + std::exception>::value, \ + const ::testing::internal::NeverThrown&, const std::exception&>::type \ + e) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } + +#else // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) + +#endif // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::TrueWithString gtest_msg{}) { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (...) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else /*NOLINT*/ \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \ + : fail(gtest_msg.value.c_str()) #if GTEST_HAS_EXCEPTIONS -#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ - catch (std::exception const& e) { \ - gtest_msg.value = ( \ - "it throws std::exception-derived exception with description: \"" \ - ); \ - gtest_msg.value += e.what(); \ - gtest_msg.value += "\"."; \ +#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ + catch (std::exception const& e) { \ + gtest_msg.value = "it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } @@ -1409,7 +1541,7 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ : public parent_class { \ public: \ - GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() = default; \ ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ test_name)); \ diff --git a/googletest/include/gtest/internal/gtest-param-util.h b/googletest/include/gtest/internal/gtest-param-util.h index f26d7d1186..138d372e06 100644 --- a/googletest/include/gtest/internal/gtest-param-util.h +++ b/googletest/include/gtest/internal/gtest-param-util.h @@ -783,10 +783,15 @@ internal::ParamGenerator ValuesIn( namespace internal { // Used in the Values() function to provide polymorphic capabilities. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template class ValueArray { public: - ValueArray(Ts... v) : v_{std::move(v)...} {} + explicit ValueArray(Ts... v) : v_(std::move(v)...) {} template operator ParamGenerator() const { // NOLINT @@ -802,6 +807,10 @@ class ValueArray { FlatTuple v_; }; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + template class CartesianProductGenerator : public ParamGeneratorInterface<::std::tuple> { diff --git a/googletest/include/gtest/internal/gtest-string.h b/googletest/include/gtest/internal/gtest-string.h index 0b2a91a5dc..323a36e64f 100644 --- a/googletest/include/gtest/internal/gtest-string.h +++ b/googletest/include/gtest/internal/gtest-string.h @@ -149,6 +149,9 @@ class GTEST_API_ String { // Formats an int value as "%02d". static std::string FormatIntWidth2(int value); // "%02d" for width == 2 + // Formats an int value to given width with leading zeros. + static std::string FormatIntWidthN(int value, int width); + // Formats an int value as "%X". static std::string FormatHexInt(int value); diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc index 121d2bba1e..9c54b81ff0 100644 --- a/googletest/src/gtest-death-test.cc +++ b/googletest/src/gtest-death-test.cc @@ -32,6 +32,7 @@ #include "gtest/gtest-death-test.h" +#include #include #include "gtest/internal/gtest-port.h" @@ -1225,21 +1226,9 @@ struct ExecDeathTestArgs { int close_fd; // File descriptor to close; the read end of a pipe }; -# if GTEST_OS_MAC -inline char** GetEnviron() { - // When Google Test is built as a framework on MacOS X, the environ variable - // is unavailable. Apple's documentation (man environ) recommends using - // _NSGetEnviron() instead. - return *_NSGetEnviron(); -} -# else -// Some POSIX platforms expect you to declare environ. extern "C" makes -// it reside in the global namespace. +# if GTEST_OS_QNX extern "C" char** environ; -inline char** GetEnviron() { return environ; } -# endif // GTEST_OS_MAC - -# if !GTEST_OS_QNX +# else // GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. @@ -1259,18 +1248,18 @@ static int ExecDeathTestChildMain(void* child_arg) { return EXIT_FAILURE; } - // We can safely call execve() as it's a direct system call. We + // We can safely call execv() as it's almost a direct system call. We // cannot use execvp() as it's a libc function and thus potentially - // unsafe. Since execve() doesn't search the PATH, the user must + // unsafe. Since execv() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. - execve(args->argv[0], args->argv, GetEnviron()); - DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + + execv(args->argv[0], args->argv); + DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } -# endif // !GTEST_OS_QNX +# endif // GTEST_OS_QNX # if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack @@ -1293,15 +1282,15 @@ static void StackLowerThanAddress(const void* ptr, GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static void StackLowerThanAddress(const void* ptr, bool* result) { - int dummy; - *result = (&dummy < ptr); + int dummy = 0; + *result = std::less()(&dummy, ptr); } // Make sure AddressSanitizer does not tamper with the stack here. GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static bool StackGrowsDown() { - int dummy; + int dummy = 0; bool result; StackLowerThanAddress(&dummy, &result); return result; @@ -1344,8 +1333,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. - child_pid = - spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); + child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, environ); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); diff --git a/googletest/src/gtest-filepath.cc b/googletest/src/gtest-filepath.cc index 062b95b1ff..af29768403 100644 --- a/googletest/src/gtest-filepath.cc +++ b/googletest/src/gtest-filepath.cc @@ -349,21 +349,19 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". void FilePath::Normalize() { - std::string normalized_pathname; - normalized_pathname.reserve(pathname_.length()); + auto out = pathname_.begin(); for (const char character : pathname_) { if (!IsPathSeparator(character)) { - normalized_pathname.push_back(character); - } else if (normalized_pathname.empty() || - normalized_pathname.back() != kPathSeparator) { - normalized_pathname.push_back(kPathSeparator); + *(out++) = character; + } else if (out == pathname_.begin() || *std::prev(out) != kPathSeparator) { + *(out++) = kPathSeparator; } else { continue; } } - pathname_ = normalized_pathname; + pathname_.erase(out, pathname_.end()); } } // namespace internal diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc index c180233735..3f39f71c07 100644 --- a/googletest/src/gtest-port.cc +++ b/googletest/src/gtest-port.cc @@ -198,7 +198,8 @@ size_t GetThreadCount() { if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { return 0; } - mib[5] = size / mib[4]; + + mib[5] = static_cast(size / static_cast(mib[4])); // populate array of structs struct kinfo_proc info[mib[5]]; @@ -207,8 +208,8 @@ size_t GetThreadCount() { } // exclude empty members - int nthreads = 0; - for (size_t i = 0; i < size / mib[4]; i++) { + size_t nthreads = 0; + for (size_t i = 0; i < size / static_cast(mib[4]); i++) { if (info[i].p_tid != -1) nthreads++; } diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 937556ba9d..3c32da8b6d 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -35,7 +35,6 @@ #include "gtest/gtest-spi.h" #include -#include #include #include #include @@ -44,6 +43,8 @@ #include #include +#include // NOLINT +#include #include #include #include @@ -55,8 +56,6 @@ #if GTEST_OS_LINUX -# define GTEST_HAS_GETTIMEOFDAY_ 1 - # include // NOLINT # include // NOLINT # include // NOLINT @@ -68,7 +67,6 @@ # include #elif GTEST_OS_ZOS -# define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. @@ -94,16 +92,11 @@ # include // NOLINT # if GTEST_OS_WINDOWS_MINGW -// MinGW has gettimeofday() but not _ftime64(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW #else -// Assume other platforms have gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 - // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT @@ -562,7 +555,7 @@ void TypeParameterizedTestSuiteRegistry::CheckForInstantiations() { "utilities.)" "\n\n" "To suppress this error for this test suite, insert the following line " - "(in a non-header) in the namespace it is definedin in:" + "(in a non-header) in the namespace it is defined in:" "\n\n" "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" + testcase.first + ");"; @@ -1005,42 +998,10 @@ std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { -#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) - // Difference between 1970-01-01 and 1601-01-01 in milliseconds. - // http://analogous.blogspot.com/2005/04/epoch.html - const TimeInMillis kJavaEpochToWinFileTimeDelta = - static_cast(116444736UL) * 100000UL; - const DWORD kTenthMicrosInMilliSecond = 10000; - - SYSTEMTIME now_systime; - FILETIME now_filetime; - ULARGE_INTEGER now_int64; - GetSystemTime(&now_systime); - if (SystemTimeToFileTime(&now_systime, &now_filetime)) { - now_int64.LowPart = now_filetime.dwLowDateTime; - now_int64.HighPart = now_filetime.dwHighDateTime; - now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - - kJavaEpochToWinFileTimeDelta; - return now_int64.QuadPart; - } - return 0; -#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ - __timeb64 now; - - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 - // (deprecated function) there. - GTEST_DISABLE_MSC_DEPRECATED_PUSH_() - _ftime64(&now); - GTEST_DISABLE_MSC_DEPRECATED_POP_() - - return static_cast(now.time) * 1000 + now.millitm; -#elif GTEST_HAS_GETTIMEOFDAY_ - struct timeval now; - gettimeofday(&now, nullptr); - return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; -#else -# error "Don't know how to get the current time on your system." -#endif + return std::chrono::duration_cast( + std::chrono::system_clock::now() - + std::chrono::system_clock::from_time_t(0)) + .count(); } // Utilities @@ -1555,6 +1516,31 @@ AssertionResult DoubleNearPredFormat(const char* expr1, const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); + // Find the value which is closest to zero. + const double min_abs = std::min(fabs(val1), fabs(val2)); + // Find the distance to the next double from that value. + const double epsilon = + nextafter(min_abs, std::numeric_limits::infinity()) - min_abs; + // Detect the case where abs_error is so small that EXPECT_NEAR is + // effectively the same as EXPECT_EQUAL, and give an informative error + // message so that the situation can be more easily understood without + // requiring exotic floating-point knowledge. + // Don't do an epsilon check if abs_error is zero because that implies + // that an equality check was actually intended. + if (!(std::isnan)(val1) && !(std::isnan)(val2) && abs_error > 0 && + abs_error < epsilon) { + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 << " is " + << diff << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ".\nThe abs_error parameter " + << abs_error_expr << " evaluates to " << abs_error + << " which is smaller than the minimum distance between doubles for " + "numbers of this magnitude which is " + << epsilon + << ", thus making this EXPECT_NEAR check equivalent to " + "EXPECT_EQUAL. Consider using EXPECT_DOUBLE_EQ instead."; + } return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" @@ -2141,8 +2127,13 @@ bool String::EndsWithCaseInsensitive( // Formats an int value as "%02d". std::string String::FormatIntWidth2(int value) { + return FormatIntWidthN(value, 2); +} + +// Formats an int value to given width with leading zeros. +std::string String::FormatIntWidthN(int value, int width) { std::stringstream ss; - ss << std::setfill('0') << std::setw(2) << value; + ss << std::setfill('0') << std::setw(width) << value; return ss.str(); } @@ -3007,9 +2998,9 @@ void TestSuite::Run() { // Call both legacy and the new API repeater->OnTestSuiteStart(*this); // Legacy API is deprecated but still available -#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ repeater->OnTestCaseStart(*this); -#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( @@ -3034,9 +3025,9 @@ void TestSuite::Run() { // Call both legacy and the new API repeater->OnTestSuiteEnd(*this); // Legacy API is deprecated but still available -#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ repeater->OnTestCaseEnd(*this); -#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ impl->set_current_test_suite(nullptr); } @@ -3053,9 +3044,9 @@ void TestSuite::Skip() { // Call both legacy and the new API repeater->OnTestSuiteStart(*this); // Legacy API is deprecated but still available -#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ repeater->OnTestCaseStart(*this); -#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Skip(); @@ -3064,9 +3055,9 @@ void TestSuite::Skip() { // Call both legacy and the new API repeater->OnTestSuiteEnd(*this); // Legacy API is deprecated but still available -#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ repeater->OnTestCaseEnd(*this); -#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ impl->set_current_test_suite(nullptr); } @@ -3277,7 +3268,7 @@ bool ShouldUseColor(bool stdout_is_tty) { // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. -void ColoredPrintf(GTestColor color, const char* fmt, ...) { +static void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); @@ -4101,13 +4092,14 @@ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { struct tm time_struct; if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) return ""; - // YYYY-MM-DDThh:mm:ss + // YYYY-MM-DDThh:mm:ss.sss return StreamableToString(time_struct.tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct.tm_mday) + "T" + String::FormatIntWidth2(time_struct.tm_hour) + ":" + String::FormatIntWidth2(time_struct.tm_min) + ":" + - String::FormatIntWidth2(time_struct.tm_sec); + String::FormatIntWidth2(time_struct.tm_sec) + "." + + String::FormatIntWidthN(static_cast(ms % 1000), 3); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. diff --git a/googletest/test/googletest-death-test-test.cc b/googletest/test/googletest-death-test-test.cc index b0dda27fa5..c0b3d1f21d 100644 --- a/googletest/test/googletest-death-test-test.cc +++ b/googletest/test/googletest-death-test-test.cc @@ -298,6 +298,13 @@ TEST(ExitStatusPredicateTest, KilledBySignal) { # endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA +// The following code intentionally tests a suboptimal syntax. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-else" +#pragma GCC diagnostic ignored "-Wempty-body" +#pragma GCC diagnostic ignored "-Wpragmas" +#endif // Tests that the death test macros expand to code which may or may not // be followed by operator<<, and that in either case the complete text // comprises only a single C++ statement. @@ -321,6 +328,9 @@ TEST_F(TestForDeathTest, SingleStatement) { else EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3; } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif # if GTEST_USES_PCRE @@ -1376,7 +1386,11 @@ void DieWithMessage(const char* message) { TEST(MatcherDeathTest, DoesNotBreakBareRegexMatching) { // googletest tests this, of course; here we ensure that including googlemock // has not broken it. +#if GTEST_USES_POSIX_RE EXPECT_DEATH(DieWithMessage("O, I die, Horatio."), "I d[aeiou]e"); +#else + EXPECT_DEATH(DieWithMessage("O, I die, Horatio."), "I di?e"); +#endif } TEST(MatcherDeathTest, MonomorphicMatcherMatches) { @@ -1464,6 +1478,13 @@ TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) { namespace { +// The following code intentionally tests a suboptimal syntax. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-else" +#pragma GCC diagnostic ignored "-Wempty-body" +#pragma GCC diagnostic ignored "-Wpragmas" +#endif // Tests that the death test macros expand to code which may or may not // be followed by operator<<, and that in either case the complete text // comprises only a single C++ statement. @@ -1489,6 +1510,9 @@ TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) { else EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3; } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif // Tests that conditional death test macros expand to code which interacts // well with switch statements. diff --git a/googletest/test/googletest-output-test-golden-lin.txt b/googletest/test/googletest-output-test-golden-lin.txt index 9ad927d53e..3fab3b97d8 100644 --- a/googletest/test/googletest-output-test-golden-lin.txt +++ b/googletest/test/googletest-output-test-golden-lin.txt @@ -1013,7 +1013,7 @@ Type parameterized test suite DetectNotInstantiatedTypesTest is defined via REGI Ideally, TYPED_TEST_P definitions should only ever be included as part of binaries that intend to use them. (As opposed to, for example, being placed in a library that may be linked in to get other utilities.) -To suppress this error for this test suite, insert the following line (in a non-header) in the namespace it is definedin in: +To suppress this error for this test suite, insert the following line (in a non-header) in the namespace it is defined in: GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DetectNotInstantiatedTypesTest); Stack trace: (omitted) diff --git a/googletest/test/googletest-port-test.cc b/googletest/test/googletest-port-test.cc index 44b99ce572..4a87df0b82 100644 --- a/googletest/test/googletest-port-test.cc +++ b/googletest/test/googletest-port-test.cc @@ -201,6 +201,13 @@ TEST(ImplicitCastTest, CanUseImplicitConstructor) { EXPECT_TRUE(converted); } +// The following code intentionally tests a suboptimal syntax. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-else" +#pragma GCC diagnostic ignored "-Wempty-body" +#pragma GCC diagnostic ignored "-Wpragmas" +#endif TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) { if (AlwaysFalse()) GTEST_CHECK_(false) << "This should never be executed; " @@ -216,6 +223,9 @@ TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) { else GTEST_CHECK_(true) << ""; } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif TEST(GtestCheckSyntaxTest, WorksWithSwitch) { switch (0) { diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index ba2befb8fc..c81af37198 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -90,6 +90,18 @@ class BiggestIntConvertible { operator ::testing::internal::BiggestInt() const { return 42; } }; +// A parent class with two child classes. The parent and one of the kids have +// stream operators. +class ParentClass {}; +class ChildClassWithStreamOperator : public ParentClass {}; +class ChildClassWithoutStreamOperator : public ParentClass {}; +static void operator<<(std::ostream& os, const ParentClass&) { + os << "ParentClass"; +} +static void operator<<(std::ostream& os, const ChildClassWithStreamOperator&) { + os << "ChildClassWithStreamOperator"; +} + // A user-defined unprintable class template in the global namespace. template class UnprintableTemplateInGlobal { @@ -177,6 +189,17 @@ inline ::std::ostream& operator<<(::std::ostream& os, return os << "StreamableTemplateInFoo: " << x.value(); } +// A user-defined streamable type in a user namespace whose operator<< is +// templated on the type of the output stream. +struct TemplatedStreamableInFoo {}; + +template +OutputStream& operator<<(OutputStream& os, + const TemplatedStreamableInFoo& /*ts*/) { + os << "TemplatedStreamableInFoo"; + return os; +} + // A user-defined streamable but recursivly-defined container type in // a user namespace, it mimics therefore std::filesystem::path or // boost::filesystem::path. @@ -1201,6 +1224,20 @@ TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) { Print(::foo::StreamableTemplateInFoo())); } +TEST(PrintStreamableTypeTest, TypeInUserNamespaceWithTemplatedStreamOperator) { + EXPECT_EQ("TemplatedStreamableInFoo", + Print(::foo::TemplatedStreamableInFoo())); +} + +TEST(PrintStreamableTypeTest, SubclassUsesSuperclassStreamOperator) { + ParentClass parent; + ChildClassWithStreamOperator child_stream; + ChildClassWithoutStreamOperator child_no_stream; + EXPECT_EQ("ParentClass", Print(parent)); + EXPECT_EQ("ChildClassWithStreamOperator", Print(child_stream)); + EXPECT_EQ("ParentClass", Print(child_no_stream)); +} + // Tests printing a user-defined recursive container type that has a << // operator. TEST(PrintStreamableTypeTest, PathLikeInUserNamespace) { diff --git a/googletest/test/googletest-shuffle-test_.cc b/googletest/test/googletest-shuffle-test_.cc index c1fc106686..4505663ae4 100644 --- a/googletest/test/googletest-shuffle-test_.cc +++ b/googletest/test/googletest-shuffle-test_.cc @@ -82,7 +82,7 @@ class TestNamePrinter : public EmptyTestEventListener { } void OnTestStart(const TestInfo& test_info) override { - printf("%s.%s\n", test_info.test_case_name(), test_info.name()); + printf("%s.%s\n", test_info.test_suite_name(), test_info.name()); } }; diff --git a/googletest/test/gtest-typed-test_test.cc b/googletest/test/gtest-typed-test_test.cc index 0c1f660fb5..de1db0cb98 100644 --- a/googletest/test/gtest-typed-test_test.cc +++ b/googletest/test/gtest-typed-test_test.cc @@ -193,13 +193,13 @@ TYPED_TEST(TypedTestWithNames, TestSuiteName) { if (std::is_same::value) { EXPECT_STREQ(::testing::UnitTest::GetInstance() ->current_test_info() - ->test_case_name(), + ->test_suite_name(), "TypedTestWithNames/char0"); } if (std::is_same::value) { EXPECT_STREQ(::testing::UnitTest::GetInstance() ->current_test_info() - ->test_case_name(), + ->test_suite_name(), "TypedTestWithNames/int1"); } } @@ -315,13 +315,13 @@ TYPED_TEST_P(TypeParametrizedTestWithNames, TestSuiteName) { if (std::is_same::value) { EXPECT_STREQ(::testing::UnitTest::GetInstance() ->current_test_info() - ->test_case_name(), + ->test_suite_name(), "CustomName/TypeParametrizedTestWithNames/parChar0"); } if (std::is_same::value) { EXPECT_STREQ(::testing::UnitTest::GetInstance() ->current_test_info() - ->test_case_name(), + ->test_suite_name(), "CustomName/TypeParametrizedTestWithNames/parInt1"); } } diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index a6d44abdb0..56bfa8c5c3 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -64,6 +64,7 @@ TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) { #include #include #include +#include #include #include #include @@ -218,17 +219,18 @@ using testing::GTEST_FLAG(stream_result_to); using testing::GTEST_FLAG(throw_on_failure); using testing::IsNotSubstring; using testing::IsSubstring; +using testing::kMaxStackTraceDepth; using testing::Message; using testing::ScopedFakeTestPartResultReporter; using testing::StaticAssertTypeEq; using testing::Test; -using testing::TestCase; using testing::TestEventListeners; using testing::TestInfo; using testing::TestPartResult; using testing::TestPartResultArray; using testing::TestProperty; using testing::TestResult; +using testing::TestSuite; using testing::TimeInMillis; using testing::UnitTest; using testing::internal::AlwaysFalse; @@ -244,7 +246,6 @@ using testing::internal::FloatingPoint; using testing::internal::ForEach; using testing::internal::FormatEpochTimeInMillisAsIso8601; using testing::internal::FormatTimeInMillisAsSeconds; -using testing::internal::GTestFlagSaver; using testing::internal::GetCurrentOsStackTraceExceptTop; using testing::internal::GetElementOr; using testing::internal::GetNextRandomSeed; @@ -253,11 +254,14 @@ using testing::internal::GetTestTypeId; using testing::internal::GetTimeInMillis; using testing::internal::GetTypeId; using testing::internal::GetUnitTestImpl; +using testing::internal::GTestFlagSaver; +using testing::internal::HasDebugStringAndShortDebugString; using testing::internal::Int32FromEnvOrDie; -using testing::internal::IsAProtocolMessage; using testing::internal::IsContainer; using testing::internal::IsContainerTest; using testing::internal::IsNotContainer; +using testing::internal::kMaxRandomSeed; +using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::NativeArray; using testing::internal::OsStackTraceGetter; using testing::internal::OsStackTraceGetterInterface; @@ -279,9 +283,6 @@ using testing::internal::WideStringToUtf8; using testing::internal::edit_distance::CalculateOptimalEdits; using testing::internal::edit_distance::CreateUnifiedDiff; using testing::internal::edit_distance::EditType; -using testing::internal::kMaxRandomSeed; -using testing::internal::kTestTypeIdInGoogleTest; -using testing::kMaxStackTraceDepth; #if GTEST_HAS_STREAM_REDIRECTION using testing::internal::CaptureStdout; @@ -485,28 +486,28 @@ class FormatEpochTimeInMillisAsIso8601Test : public Test { const TimeInMillis FormatEpochTimeInMillisAsIso8601Test::kMillisPerSec; TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsTwoDigitSegments) { - EXPECT_EQ("2011-10-31T18:52:42", + EXPECT_EQ("2011-10-31T18:52:42.000", FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec)); } -TEST_F(FormatEpochTimeInMillisAsIso8601Test, MillisecondsDoNotAffectResult) { +TEST_F(FormatEpochTimeInMillisAsIso8601Test, IncludesMillisecondsAfterDot) { EXPECT_EQ( - "2011-10-31T18:52:42", + "2011-10-31T18:52:42.234", FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec + 234)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsLeadingZeroes) { - EXPECT_EQ("2011-09-03T05:07:02", + EXPECT_EQ("2011-09-03T05:07:02.000", FormatEpochTimeInMillisAsIso8601(1315026422 * kMillisPerSec)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, Prints24HourTime) { - EXPECT_EQ("2011-09-28T17:08:22", + EXPECT_EQ("2011-09-28T17:08:22.000", FormatEpochTimeInMillisAsIso8601(1317229702 * kMillisPerSec)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsEpochStart) { - EXPECT_EQ("1970-01-01T00:00:00", FormatEpochTimeInMillisAsIso8601(0)); + EXPECT_EQ("1970-01-01T00:00:00.000", FormatEpochTimeInMillisAsIso8601(0)); } # ifdef __BORLANDC__ @@ -2767,7 +2768,7 @@ class FloatingPointTest : public Test { typedef typename Floating::Bits Bits; void SetUp() override { - const size_t max_ulps = Floating::kMaxUlps; + const uint32_t max_ulps = Floating::kMaxUlps; // The bits that represent 0.0. const Bits zero_bits = Floating(0).bits(); @@ -3084,6 +3085,13 @@ TEST_F(DoubleTest, EXPECT_NEAR) { EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, 1.5, 0.25), // NOLINT "The difference between 1.0 and 1.5 is 0.5, " "which exceeds 0.25"); + // At this magnitude adjacent doubles are 512.0 apart, so this triggers a + // slightly different failure reporting path. + EXPECT_NONFATAL_FAILURE( + EXPECT_NEAR(4.2934311416234112e+18, 4.2934311416234107e+18, 1.0), + "The abs_error parameter 1.0 evaluates to 1 which is smaller than the " + "minimum distance between doubles for numbers of this magnitude which is " + "512"); } // Tests ASSERT_NEAR. @@ -3345,6 +3353,16 @@ TEST_F(SingleEvaluationTest, OtherCases) { #if GTEST_HAS_EXCEPTIONS +#if GTEST_HAS_RTTI + +#define ERROR_DESC "std::runtime_error" + +#else // GTEST_HAS_RTTI + +#define ERROR_DESC "an std::exception-derived error" + +#endif // GTEST_HAS_RTTI + void ThrowAnInteger() { throw 1; } @@ -3368,31 +3386,38 @@ TEST_F(SingleEvaluationTest, ExceptionTests) { }, bool), "throws a different type"); EXPECT_EQ(2, a_); + // failed EXPECT_THROW, throws runtime error + EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT + a_++; + ThrowRuntimeError("A description"); + }, bool), "throws " ERROR_DESC " with description \"A description\""); + EXPECT_EQ(3, a_); + // failed EXPECT_THROW, throws nothing EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing"); - EXPECT_EQ(3, a_); + EXPECT_EQ(4, a_); // successful EXPECT_NO_THROW EXPECT_NO_THROW(a_++); - EXPECT_EQ(4, a_); + EXPECT_EQ(5, a_); // failed EXPECT_NO_THROW EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT a_++; ThrowAnInteger(); }), "it throws"); - EXPECT_EQ(5, a_); + EXPECT_EQ(6, a_); // successful EXPECT_ANY_THROW EXPECT_ANY_THROW({ // NOLINT a_++; ThrowAnInteger(); }); - EXPECT_EQ(6, a_); + EXPECT_EQ(7, a_); // failed EXPECT_ANY_THROW EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't"); - EXPECT_EQ(7, a_); + EXPECT_EQ(8, a_); } #endif // GTEST_HAS_EXCEPTIONS @@ -3812,6 +3837,12 @@ TEST(AssertionTest, ASSERT_THROW) { ASSERT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of type bool.\n" " Actual: it throws a different type."); + EXPECT_FATAL_FAILURE( + ASSERT_THROW(ThrowRuntimeError("A description"), std::logic_error), + "Expected: ThrowRuntimeError(\"A description\") " + "throws an exception of type std::logic_error.\n " + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); # endif EXPECT_FATAL_FAILURE( @@ -3829,8 +3860,8 @@ TEST(AssertionTest, ASSERT_NO_THROW) { EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowRuntimeError("A description")), "Expected: ThrowRuntimeError(\"A description\") " "doesn't throw an exception.\n " - "Actual: it throws std::exception-derived exception " - "with description: \"A description\"."); + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); } // Tests ASSERT_ANY_THROW. @@ -4100,11 +4131,13 @@ TEST(HRESULTAssertionTest, Streaming) { #endif // GTEST_OS_WINDOWS -#ifdef __BORLANDC__ -// Silences warnings: "Condition is always true", "Unreachable code" -# pragma option push -w-ccc -w-rch +// The following code intentionally tests a suboptimal syntax. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-else" +#pragma GCC diagnostic ignored "-Wempty-body" +#pragma GCC diagnostic ignored "-Wpragmas" #endif - // Tests that the assertion macros behave like single statements. TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) @@ -4124,6 +4157,9 @@ TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement) { else EXPECT_GT(3, 2) << ""; } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif #if GTEST_HAS_EXCEPTIONS // Tests that the compiler will not complain about unreachable code in the @@ -4140,6 +4176,17 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(n++), ""); } +TEST(ExpectThrowTest, DoesNotGenerateDuplicateCatchClauseWarning) { + EXPECT_THROW(throw std::exception(), std::exception); +} + +// The following code intentionally tests a suboptimal syntax. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-else" +#pragma GCC diagnostic ignored "-Wempty-body" +#pragma GCC diagnostic ignored "-Wpragmas" +#endif TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) EXPECT_THROW(ThrowNothing(), bool); @@ -4165,8 +4212,19 @@ TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { else ; // NOLINT } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + #endif // GTEST_HAS_EXCEPTIONS +// The following code intentionally tests a suboptimal syntax. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-else" +#pragma GCC diagnostic ignored "-Wempty-body" +#pragma GCC diagnostic ignored "-Wpragmas" +#endif TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) EXPECT_NO_FATAL_FAILURE(FAIL()) << "This should never be executed. " @@ -4189,6 +4247,9 @@ TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement) { else ASSERT_NO_FATAL_FAILURE(SUCCEED()); } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif // Tests that the assertion macros work well with switch statements. TEST(AssertionSyntaxTest, WorksWithSwitch) { @@ -4550,6 +4611,12 @@ TEST(ExpectTest, EXPECT_THROW) { EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of " "type bool.\n Actual: it throws a different type."); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowRuntimeError("A description"), + std::logic_error), + "Expected: ThrowRuntimeError(\"A description\") " + "throws an exception of type std::logic_error.\n " + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); EXPECT_NONFATAL_FAILURE( EXPECT_THROW(ThrowNothing(), bool), "Expected: ThrowNothing() throws an exception of type bool.\n" @@ -4565,8 +4632,8 @@ TEST(ExpectTest, EXPECT_NO_THROW) { EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowRuntimeError("A description")), "Expected: ThrowRuntimeError(\"A description\") " "doesn't throw an exception.\n " - "Actual: it throws std::exception-derived exception " - "with description: \"A description\"."); + "Actual: it throws " ERROR_DESC " " + "with description \"A description\"."); } // Tests EXPECT_ANY_THROW. @@ -5306,7 +5373,7 @@ class TestInfoTest : public Test { TEST_F(TestInfoTest, Names) { const TestInfo* const test_info = GetTestInfo("Names"); - ASSERT_STREQ("TestInfoTest", test_info->test_case_name()); + ASSERT_STREQ("TestInfoTest", test_info->test_suite_name()); ASSERT_STREQ("Names", test_info->name()); } @@ -5376,7 +5443,7 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, CodeLocationForTYPEDTESTP, int); // Tests setting up and tearing down a test case. // Legacy API is deprecated but still available -#ifndef REMOVE_LEGACY_TEST_CASEAPI +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ class SetUpTestCaseTest : public Test { protected: // This will be called once before the first test in this test case @@ -5435,7 +5502,7 @@ TEST_F(SetUpTestCaseTest, Test1) { EXPECT_STRNE(nullptr, shared_resource_); } TEST_F(SetUpTestCaseTest, Test2) { EXPECT_STREQ("123", shared_resource_); } -#endif // REMOVE_LEGACY_TEST_CASEAPI +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Tests SetupTestSuite/TearDown TestSuite class SetUpTestSuiteTest : public Test { @@ -6341,8 +6408,8 @@ TEST_F(CurrentTestInfoTest, WorksForFirstTestInATestSuite) { UnitTest::GetInstance()->current_test_info(); ASSERT_TRUE(nullptr != test_info) << "There is a test running so we should have a valid TestInfo."; - EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) - << "Expected the name of the currently running test case."; + EXPECT_STREQ("CurrentTestInfoTest", test_info->test_suite_name()) + << "Expected the name of the currently running test suite."; EXPECT_STREQ("WorksForFirstTestInATestSuite", test_info->name()) << "Expected the name of the currently running test."; } @@ -6356,8 +6423,8 @@ TEST_F(CurrentTestInfoTest, WorksForSecondTestInATestSuite) { UnitTest::GetInstance()->current_test_info(); ASSERT_TRUE(nullptr != test_info) << "There is a test running so we should have a valid TestInfo."; - EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) - << "Expected the name of the currently running test case."; + EXPECT_STREQ("CurrentTestInfoTest", test_info->test_suite_name()) + << "Expected the name of the currently running test suite."; EXPECT_STREQ("WorksForSecondTestInATestSuite", test_info->name()) << "Expected the name of the currently running test."; } @@ -7145,24 +7212,71 @@ GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST. class ConversionHelperBase {}; class ConversionHelperDerived : public ConversionHelperBase {}; -// Tests that IsAProtocolMessage::value is a compile-time constant. -TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { - GTEST_COMPILE_ASSERT_(IsAProtocolMessage<::proto2::MessageLite>::value, - const_true); - GTEST_COMPILE_ASSERT_(!IsAProtocolMessage::value, const_false); -} +struct HasDebugStringMethods { + std::string DebugString() const { return ""; } + std::string ShortDebugString() const { return ""; } +}; + +struct InheritsDebugStringMethods : public HasDebugStringMethods {}; + +struct WrongTypeDebugStringMethod { + std::string DebugString() const { return ""; } + int ShortDebugString() const { return 1; } +}; -// Tests that IsAProtocolMessage::value is true when T is -// proto2::Message or a sub-class of it. -TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { - EXPECT_TRUE(IsAProtocolMessage<::proto2::MessageLite>::value); +struct NotConstDebugStringMethod { + std::string DebugString() { return ""; } + std::string ShortDebugString() const { return ""; } +}; + +struct MissingDebugStringMethod { + std::string DebugString() { return ""; } +}; + +struct IncompleteType; + +// Tests that HasDebugStringAndShortDebugString::value is a compile-time +// constant. +TEST(HasDebugStringAndShortDebugStringTest, ValueIsCompileTimeConstant) { + GTEST_COMPILE_ASSERT_( + HasDebugStringAndShortDebugString::value, + const_true); + GTEST_COMPILE_ASSERT_( + HasDebugStringAndShortDebugString::value, + const_true); + GTEST_COMPILE_ASSERT_(HasDebugStringAndShortDebugString< + const InheritsDebugStringMethods>::value, + const_true); + GTEST_COMPILE_ASSERT_( + !HasDebugStringAndShortDebugString::value, + const_false); + GTEST_COMPILE_ASSERT_( + !HasDebugStringAndShortDebugString::value, + const_false); + GTEST_COMPILE_ASSERT_( + !HasDebugStringAndShortDebugString::value, + const_false); + GTEST_COMPILE_ASSERT_( + !HasDebugStringAndShortDebugString::value, const_false); + GTEST_COMPILE_ASSERT_(!HasDebugStringAndShortDebugString::value, + const_false); +} + +// Tests that HasDebugStringAndShortDebugString::value is true when T has +// needed methods. +TEST(HasDebugStringAndShortDebugStringTest, + ValueIsTrueWhenTypeHasDebugStringAndShortDebugString) { + EXPECT_TRUE( + HasDebugStringAndShortDebugString::value); } -// Tests that IsAProtocolMessage::value is false when T is neither -// ::proto2::Message nor a sub-class of it. -TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) { - EXPECT_FALSE(IsAProtocolMessage::value); - EXPECT_FALSE(IsAProtocolMessage::value); +// Tests that HasDebugStringAndShortDebugString::value is false when T +// doesn't have needed methods. +TEST(HasDebugStringAndShortDebugStringTest, + ValueIsFalseWhenTypeIsNotAProtocolMessage) { + EXPECT_FALSE(HasDebugStringAndShortDebugString::value); + EXPECT_FALSE( + HasDebugStringAndShortDebugString::value); } // Tests GTEST_REMOVE_REFERENCE_AND_CONST_. @@ -7446,6 +7560,142 @@ TEST(FlatTuple, Basic) { EXPECT_EQ(5.1, tuple.Get<1>()); } +namespace { +std::string AddIntToString(int i, const std::string& s) { + return s + std::to_string(i); +} +} // namespace + +TEST(FlatTuple, Apply) { + using testing::internal::FlatTuple; + + FlatTuple tuple{5, "Hello"}; + + // Lambda. + EXPECT_TRUE(tuple.Apply([](int i, const std::string& s) -> bool { + return i == static_cast(s.size()); + })); + + // Function. + EXPECT_EQ(tuple.Apply(AddIntToString), "Hello5"); + + // Mutating operations. + tuple.Apply([](int& i, std::string& s) { + ++i; + s += s; + }); + EXPECT_EQ(tuple.Get<0>(), 6); + EXPECT_EQ(tuple.Get<1>(), "HelloHello"); +} + +struct ConstructionCounting { + ConstructionCounting() { ++default_ctor_calls; } + ~ConstructionCounting() { ++dtor_calls; } + ConstructionCounting(const ConstructionCounting&) { ++copy_ctor_calls; } + ConstructionCounting(ConstructionCounting&&) noexcept { ++move_ctor_calls; } + ConstructionCounting& operator=(const ConstructionCounting&) { + ++copy_assignment_calls; + return *this; + } + ConstructionCounting& operator=(ConstructionCounting&&) noexcept { + ++move_assignment_calls; + return *this; + } + + static void Reset() { + default_ctor_calls = 0; + dtor_calls = 0; + copy_ctor_calls = 0; + move_ctor_calls = 0; + copy_assignment_calls = 0; + move_assignment_calls = 0; + } + + static int default_ctor_calls; + static int dtor_calls; + static int copy_ctor_calls; + static int move_ctor_calls; + static int copy_assignment_calls; + static int move_assignment_calls; +}; + +int ConstructionCounting::default_ctor_calls = 0; +int ConstructionCounting::dtor_calls = 0; +int ConstructionCounting::copy_ctor_calls = 0; +int ConstructionCounting::move_ctor_calls = 0; +int ConstructionCounting::copy_assignment_calls = 0; +int ConstructionCounting::move_assignment_calls = 0; + +TEST(FlatTuple, ConstructorCalls) { + using testing::internal::FlatTuple; + + // Default construction. + ConstructionCounting::Reset(); + { FlatTuple tuple; } + EXPECT_EQ(ConstructionCounting::default_ctor_calls, 1); + EXPECT_EQ(ConstructionCounting::dtor_calls, 1); + EXPECT_EQ(ConstructionCounting::copy_ctor_calls, 0); + EXPECT_EQ(ConstructionCounting::move_ctor_calls, 0); + EXPECT_EQ(ConstructionCounting::copy_assignment_calls, 0); + EXPECT_EQ(ConstructionCounting::move_assignment_calls, 0); + + // Copy construction. + ConstructionCounting::Reset(); + { + ConstructionCounting elem; + FlatTuple tuple{elem}; + } + EXPECT_EQ(ConstructionCounting::default_ctor_calls, 1); + EXPECT_EQ(ConstructionCounting::dtor_calls, 2); + EXPECT_EQ(ConstructionCounting::copy_ctor_calls, 1); + EXPECT_EQ(ConstructionCounting::move_ctor_calls, 0); + EXPECT_EQ(ConstructionCounting::copy_assignment_calls, 0); + EXPECT_EQ(ConstructionCounting::move_assignment_calls, 0); + + // Move construction. + ConstructionCounting::Reset(); + { FlatTuple tuple{ConstructionCounting{}}; } + EXPECT_EQ(ConstructionCounting::default_ctor_calls, 1); + EXPECT_EQ(ConstructionCounting::dtor_calls, 2); + EXPECT_EQ(ConstructionCounting::copy_ctor_calls, 0); + EXPECT_EQ(ConstructionCounting::move_ctor_calls, 1); + EXPECT_EQ(ConstructionCounting::copy_assignment_calls, 0); + EXPECT_EQ(ConstructionCounting::move_assignment_calls, 0); + + // Copy assignment. + // TODO(ofats): it should be testing assignment operator of FlatTuple, not its + // elements + ConstructionCounting::Reset(); + { + FlatTuple tuple; + ConstructionCounting elem; + tuple.Get<0>() = elem; + } + EXPECT_EQ(ConstructionCounting::default_ctor_calls, 2); + EXPECT_EQ(ConstructionCounting::dtor_calls, 2); + EXPECT_EQ(ConstructionCounting::copy_ctor_calls, 0); + EXPECT_EQ(ConstructionCounting::move_ctor_calls, 0); + EXPECT_EQ(ConstructionCounting::copy_assignment_calls, 1); + EXPECT_EQ(ConstructionCounting::move_assignment_calls, 0); + + // Move assignment. + // TODO(ofats): it should be testing assignment operator of FlatTuple, not its + // elements + ConstructionCounting::Reset(); + { + FlatTuple tuple; + tuple.Get<0>() = ConstructionCounting{}; + } + EXPECT_EQ(ConstructionCounting::default_ctor_calls, 2); + EXPECT_EQ(ConstructionCounting::dtor_calls, 2); + EXPECT_EQ(ConstructionCounting::copy_ctor_calls, 0); + EXPECT_EQ(ConstructionCounting::move_ctor_calls, 0); + EXPECT_EQ(ConstructionCounting::copy_assignment_calls, 0); + EXPECT_EQ(ConstructionCounting::move_assignment_calls, 1); + + ConstructionCounting::Reset(); +} + TEST(FlatTuple, ManyTypes) { using testing::internal::FlatTuple; diff --git a/googletest/test/gtest_xml_test_utils.py b/googletest/test/gtest_xml_test_utils.py index cae0bc0b9a..5dd0eb9244 100755 --- a/googletest/test/gtest_xml_test_utils.py +++ b/googletest/test/gtest_xml_test_utils.py @@ -172,7 +172,7 @@ def NormalizeXml(self, element): if element.tagName in ('testsuites', 'testsuite', 'testcase'): timestamp = element.getAttributeNode('timestamp') - timestamp.value = re.sub(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d$', + timestamp.value = re.sub(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\d$', '*', timestamp.value) if element.tagName in ('testsuites', 'testsuite', 'testcase'): time = element.getAttributeNode('time') From 0561e91c262b1be3f9c5c8db050b14d06036e0d8 Mon Sep 17 00:00:00 2001 From: Chuck Atkins Date: Fri, 30 Oct 2020 11:38:32 -0400 Subject: [PATCH 02/17] Clean KWSys for update --- thirdparty/KWSys/adios2sys/.clang-format | 9 - thirdparty/KWSys/adios2sys/Base64.c | 225 - thirdparty/KWSys/adios2sys/Base64.h.in | 110 - thirdparty/KWSys/adios2sys/CMakeLists.txt | 1231 ---- thirdparty/KWSys/adios2sys/CONTRIBUTING.rst | 49 - thirdparty/KWSys/adios2sys/CTestConfig.cmake | 9 - .../KWSys/adios2sys/CTestCustom.cmake.in | 14 - .../KWSys/adios2sys/CommandLineArguments.cxx | 768 --- .../adios2sys/CommandLineArguments.hxx.in | 267 - thirdparty/KWSys/adios2sys/Configure.h.in | 124 - thirdparty/KWSys/adios2sys/Configure.hxx.in | 60 - thirdparty/KWSys/adios2sys/ConsoleBuf.hxx.in | 396 -- thirdparty/KWSys/adios2sys/Copyright.txt | 38 - thirdparty/KWSys/adios2sys/Directory.cxx | 236 - thirdparty/KWSys/adios2sys/Directory.hxx.in | 72 - thirdparty/KWSys/adios2sys/DynamicLoader.cxx | 441 -- .../KWSys/adios2sys/DynamicLoader.hxx.in | 93 - thirdparty/KWSys/adios2sys/Encoding.h.in | 69 - thirdparty/KWSys/adios2sys/Encoding.hxx.in | 78 - thirdparty/KWSys/adios2sys/EncodingC.c | 72 - thirdparty/KWSys/adios2sys/EncodingCXX.cxx | 277 - thirdparty/KWSys/adios2sys/ExtraTest.cmake.in | 1 - thirdparty/KWSys/adios2sys/FStream.cxx | 55 - thirdparty/KWSys/adios2sys/FStream.hxx.in | 276 - thirdparty/KWSys/adios2sys/Glob.cxx | 447 -- thirdparty/KWSys/adios2sys/Glob.hxx.in | 142 - thirdparty/KWSys/adios2sys/IOStream.cxx | 255 - thirdparty/KWSys/adios2sys/IOStream.hxx.in | 126 - thirdparty/KWSys/adios2sys/MD5.c | 494 -- thirdparty/KWSys/adios2sys/MD5.h.in | 97 - thirdparty/KWSys/adios2sys/Process.h.in | 540 -- thirdparty/KWSys/adios2sys/ProcessUNIX.c | 2920 --------- thirdparty/KWSys/adios2sys/ProcessWin32.c | 2772 --------- thirdparty/KWSys/adios2sys/README.rst | 37 - .../KWSys/adios2sys/RegularExpression.cxx | 1216 ---- .../KWSys/adios2sys/RegularExpression.hxx.in | 548 -- thirdparty/KWSys/adios2sys/SharedForward.h.in | 876 --- thirdparty/KWSys/adios2sys/String.c | 100 - thirdparty/KWSys/adios2sys/String.h.in | 57 - thirdparty/KWSys/adios2sys/String.hxx.in | 65 - thirdparty/KWSys/adios2sys/System.c | 236 - thirdparty/KWSys/adios2sys/System.h.in | 59 - .../KWSys/adios2sys/SystemInformation.cxx | 5428 ----------------- .../KWSys/adios2sys/SystemInformation.hxx.in | 167 - thirdparty/KWSys/adios2sys/SystemTools.cxx | 4724 -------------- thirdparty/KWSys/adios2sys/SystemTools.hxx.in | 1003 --- thirdparty/KWSys/adios2sys/Terminal.c | 402 -- thirdparty/KWSys/adios2sys/Terminal.h.in | 170 - thirdparty/KWSys/adios2sys/hash_fun.hxx.in | 166 - thirdparty/KWSys/adios2sys/hash_map.hxx.in | 423 -- thirdparty/KWSys/adios2sys/hash_set.hxx.in | 392 -- thirdparty/KWSys/adios2sys/hashtable.hxx.in | 992 --- thirdparty/KWSys/adios2sys/kwsysHeaderDump.pl | 41 - .../KWSys/adios2sys/kwsysPlatformTests.cmake | 211 - .../KWSys/adios2sys/kwsysPlatformTestsC.c | 108 - .../KWSys/adios2sys/kwsysPlatformTestsCXX.cxx | 377 -- thirdparty/KWSys/adios2sys/kwsysPrivate.h | 34 - .../adios2sys/testCommandLineArguments.cxx | 208 - .../adios2sys/testCommandLineArguments1.cxx | 93 - thirdparty/KWSys/adios2sys/testConfigure.cxx | 30 - thirdparty/KWSys/adios2sys/testConsoleBuf.cxx | 773 --- thirdparty/KWSys/adios2sys/testConsoleBuf.hxx | 17 - .../KWSys/adios2sys/testConsoleBufChild.cxx | 55 - thirdparty/KWSys/adios2sys/testDirectory.cxx | 79 - .../KWSys/adios2sys/testDynamicLoader.cxx | 117 - thirdparty/KWSys/adios2sys/testDynload.c | 13 - thirdparty/KWSys/adios2sys/testEncode.c | 67 - thirdparty/KWSys/adios2sys/testEncoding.cxx | 286 - thirdparty/KWSys/adios2sys/testFStream.cxx | 113 - thirdparty/KWSys/adios2sys/testFail.c | 24 - thirdparty/KWSys/adios2sys/testHashSTL.cxx | 63 - thirdparty/KWSys/adios2sys/testProcess.c | 725 --- .../KWSys/adios2sys/testSharedForward.c.in | 27 - .../KWSys/adios2sys/testSystemInformation.cxx | 106 - .../KWSys/adios2sys/testSystemTools.bin | Bin 766 -> 0 bytes .../KWSys/adios2sys/testSystemTools.cxx | 957 --- .../KWSys/adios2sys/testSystemTools.h.in | 12 - thirdparty/KWSys/adios2sys/testTerminal.c | 22 - 78 files changed, 34382 deletions(-) delete mode 100644 thirdparty/KWSys/adios2sys/.clang-format delete mode 100644 thirdparty/KWSys/adios2sys/Base64.c delete mode 100644 thirdparty/KWSys/adios2sys/Base64.h.in delete mode 100644 thirdparty/KWSys/adios2sys/CMakeLists.txt delete mode 100644 thirdparty/KWSys/adios2sys/CONTRIBUTING.rst delete mode 100644 thirdparty/KWSys/adios2sys/CTestConfig.cmake delete mode 100644 thirdparty/KWSys/adios2sys/CTestCustom.cmake.in delete mode 100644 thirdparty/KWSys/adios2sys/CommandLineArguments.cxx delete mode 100644 thirdparty/KWSys/adios2sys/CommandLineArguments.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/Configure.h.in delete mode 100644 thirdparty/KWSys/adios2sys/Configure.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/ConsoleBuf.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/Copyright.txt delete mode 100644 thirdparty/KWSys/adios2sys/Directory.cxx delete mode 100644 thirdparty/KWSys/adios2sys/Directory.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/DynamicLoader.cxx delete mode 100644 thirdparty/KWSys/adios2sys/DynamicLoader.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/Encoding.h.in delete mode 100644 thirdparty/KWSys/adios2sys/Encoding.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/EncodingC.c delete mode 100644 thirdparty/KWSys/adios2sys/EncodingCXX.cxx delete mode 100644 thirdparty/KWSys/adios2sys/ExtraTest.cmake.in delete mode 100644 thirdparty/KWSys/adios2sys/FStream.cxx delete mode 100644 thirdparty/KWSys/adios2sys/FStream.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/Glob.cxx delete mode 100644 thirdparty/KWSys/adios2sys/Glob.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/IOStream.cxx delete mode 100644 thirdparty/KWSys/adios2sys/IOStream.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/MD5.c delete mode 100644 thirdparty/KWSys/adios2sys/MD5.h.in delete mode 100644 thirdparty/KWSys/adios2sys/Process.h.in delete mode 100644 thirdparty/KWSys/adios2sys/ProcessUNIX.c delete mode 100644 thirdparty/KWSys/adios2sys/ProcessWin32.c delete mode 100644 thirdparty/KWSys/adios2sys/README.rst delete mode 100644 thirdparty/KWSys/adios2sys/RegularExpression.cxx delete mode 100644 thirdparty/KWSys/adios2sys/RegularExpression.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/SharedForward.h.in delete mode 100644 thirdparty/KWSys/adios2sys/String.c delete mode 100644 thirdparty/KWSys/adios2sys/String.h.in delete mode 100644 thirdparty/KWSys/adios2sys/String.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/System.c delete mode 100644 thirdparty/KWSys/adios2sys/System.h.in delete mode 100644 thirdparty/KWSys/adios2sys/SystemInformation.cxx delete mode 100644 thirdparty/KWSys/adios2sys/SystemInformation.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/SystemTools.cxx delete mode 100644 thirdparty/KWSys/adios2sys/SystemTools.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/Terminal.c delete mode 100644 thirdparty/KWSys/adios2sys/Terminal.h.in delete mode 100644 thirdparty/KWSys/adios2sys/hash_fun.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/hash_map.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/hash_set.hxx.in delete mode 100644 thirdparty/KWSys/adios2sys/hashtable.hxx.in delete mode 100755 thirdparty/KWSys/adios2sys/kwsysHeaderDump.pl delete mode 100644 thirdparty/KWSys/adios2sys/kwsysPlatformTests.cmake delete mode 100644 thirdparty/KWSys/adios2sys/kwsysPlatformTestsC.c delete mode 100644 thirdparty/KWSys/adios2sys/kwsysPlatformTestsCXX.cxx delete mode 100644 thirdparty/KWSys/adios2sys/kwsysPrivate.h delete mode 100644 thirdparty/KWSys/adios2sys/testCommandLineArguments.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testCommandLineArguments1.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testConfigure.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testConsoleBuf.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testConsoleBuf.hxx delete mode 100644 thirdparty/KWSys/adios2sys/testConsoleBufChild.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testDirectory.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testDynamicLoader.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testDynload.c delete mode 100644 thirdparty/KWSys/adios2sys/testEncode.c delete mode 100644 thirdparty/KWSys/adios2sys/testEncoding.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testFStream.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testFail.c delete mode 100644 thirdparty/KWSys/adios2sys/testHashSTL.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testProcess.c delete mode 100644 thirdparty/KWSys/adios2sys/testSharedForward.c.in delete mode 100644 thirdparty/KWSys/adios2sys/testSystemInformation.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testSystemTools.bin delete mode 100644 thirdparty/KWSys/adios2sys/testSystemTools.cxx delete mode 100644 thirdparty/KWSys/adios2sys/testSystemTools.h.in delete mode 100644 thirdparty/KWSys/adios2sys/testTerminal.c diff --git a/thirdparty/KWSys/adios2sys/.clang-format b/thirdparty/KWSys/adios2sys/.clang-format deleted file mode 100644 index a8bde417dd..0000000000 --- a/thirdparty/KWSys/adios2sys/.clang-format +++ /dev/null @@ -1,9 +0,0 @@ ---- -# This configuration requires clang-format 3.8 or higher. -BasedOnStyle: Mozilla -AlignOperands: false -AlwaysBreakAfterReturnType: None -AlwaysBreakAfterDefinitionReturnType: None -ColumnLimit: 79 -Standard: Cpp03 -... diff --git a/thirdparty/KWSys/adios2sys/Base64.c b/thirdparty/KWSys/adios2sys/Base64.c deleted file mode 100644 index 99f008e595..0000000000 --- a/thirdparty/KWSys/adios2sys/Base64.c +++ /dev/null @@ -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); -} diff --git a/thirdparty/KWSys/adios2sys/Base64.h.in b/thirdparty/KWSys/adios2sys/Base64.h.in deleted file mode 100644 index 35367574ae..0000000000 --- a/thirdparty/KWSys/adios2sys/Base64.h.in +++ /dev/null @@ -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 /* size_t */ - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -#define kwsys_ns(x) @KWSYS_NAMESPACE@##x -#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#define kwsysBase64 kwsys_ns(Base64) -#define kwsysBase64_Decode kwsys_ns(Base64_Decode) -#define kwsysBase64_Decode3 kwsys_ns(Base64_Decode3) -#define kwsysBase64_Encode kwsys_ns(Base64_Encode) -#define kwsysBase64_Encode1 kwsys_ns(Base64_Encode1) -#define kwsysBase64_Encode2 kwsys_ns(Base64_Encode2) -#define kwsysBase64_Encode3 kwsys_ns(Base64_Encode3) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Encode 3 bytes into a 4 byte string. - */ -kwsysEXPORT void kwsysBase64_Encode3(const unsigned char* src, - unsigned char* dest); - -/** - * Encode 2 bytes into a 4 byte string. - */ -kwsysEXPORT void kwsysBase64_Encode2(const unsigned char* src, - unsigned char* dest); - -/** - * Encode 1 bytes into a 4 byte string. - */ -kwsysEXPORT void kwsysBase64_Encode1(const unsigned char* src, - unsigned char* dest); - -/** - * Encode 'length' bytes from the input buffer and store the encoded - * stream into the output buffer. Return the length of the encoded - * buffer (output). Note that the output buffer must be allocated by - * the caller (length * 1.5 should be a safe estimate). If 'mark_end' - * is true than an extra set of 4 bytes is added to the end of the - * stream if the input is a multiple of 3 bytes. These bytes are - * invalid chars and therefore they will stop the decoder thus - * enabling the caller to decode a stream without actually knowing how - * much data to expect (if the input is not a multiple of 3 bytes then - * the extra padding needed to complete the encode 4 bytes will stop - * the decoding anyway). - */ -kwsysEXPORT size_t kwsysBase64_Encode(const unsigned char* input, - size_t length, unsigned char* output, - int mark_end); - -/** - * Decode 4 bytes into a 3 byte string. Returns the number of bytes - * actually decoded. - */ -kwsysEXPORT int kwsysBase64_Decode3(const unsigned char* src, - unsigned char* dest); - -/** - * Decode bytes from the input buffer and store the decoded stream - * into the output buffer until 'length' bytes have been decoded. - * Return the real length of the decoded stream (which should be equal - * to 'length'). Note that the output buffer must be allocated by the - * caller. If 'max_input_length' is not null, then it specifies the - * number of encoded bytes that should be at most read from the input - * buffer. In that case the 'length' parameter is ignored. This - * enables the caller to decode a stream without actually knowing how - * much decoded data to expect (of course, the buffer must be large - * enough). - */ -kwsysEXPORT size_t kwsysBase64_Decode(const unsigned char* input, - size_t length, unsigned char* output, - size_t max_input_length); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -#undef kwsys_ns -#undef kwsysEXPORT -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#undef kwsysBase64 -#undef kwsysBase64_Decode -#undef kwsysBase64_Decode3 -#undef kwsysBase64_Encode -#undef kwsysBase64_Encode1 -#undef kwsysBase64_Encode2 -#undef kwsysBase64_Encode3 -#endif -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/CMakeLists.txt b/thirdparty/KWSys/adios2sys/CMakeLists.txt deleted file mode 100644 index bddc0886bd..0000000000 --- a/thirdparty/KWSys/adios2sys/CMakeLists.txt +++ /dev/null @@ -1,1231 +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. -# -# Example: -# -# SET(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR}) -# INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) -# -# Optional settings to setup install rules are as follows: -# -# KWSYS_INSTALL_BIN_DIR = The installation target directories into -# KWSYS_INSTALL_LIB_DIR which the libraries and headers from -# KWSYS_INSTALL_INCLUDE_DIR kwsys should be installed by a "make install". -# The values should be specified relative to -# the installation prefix and NOT start with '/'. -# KWSYS_INSTALL_DOC_DIR = The installation target directory for documentation -# such as copyright information. -# -# KWSYS_INSTALL_COMPONENT_NAME_RUNTIME = Name of runtime and development -# KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT installation components. -# If not given the install rules -# will not be in any component. -# -# KWSYS_INSTALL_EXPORT_NAME = The EXPORT option value for install(TARGETS) calls. -# -# Example: -# -# SET(KWSYS_INSTALL_BIN_DIR bin) -# SET(KWSYS_INSTALL_LIB_DIR lib) -# SET(KWSYS_INSTALL_INCLUDE_DIR include) -# SET(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime) -# SET(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development) - -# Once configured, kwsys should be used as follows from C or C++ code: -# -# #include -# ... -# foosys::Directory directory; -# - -# NOTE: This library is intended for internal use by Kitware-driven -# projects. In order to keep it simple no attempt will be made to -# maintain backward compatibility when changes are made to KWSys. -# When an incompatible change is made Kitware's projects that use -# KWSys will be fixed, but no notification will necessarily be sent to -# any outside mailing list and no documentation of the change will be -# written. - -CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3 FATAL_ERROR) -FOREACH(p - CMP0022 # CMake 2.8, Define link interface - required by android_mk export - CMP0025 # CMake 3.0, Compiler id for Apple Clang is now AppleClang. - CMP0042 # CMake 3.0, MACOSX_RPATH is enabled by default. - CMP0048 # CMake 3.0, Let the project command manage version variables. - CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature. - CMP0063 # CMake 3.3, Honor visibility properties for all target types. - ) - IF(POLICY ${p}) - CMAKE_POLICY(SET ${p} NEW) - ENDIF() -ENDFOREACH() -SET(CMAKE_LEGACY_CYGWIN_WIN32 0) - -IF(CMAKE_VERSION VERSION_LESS 3.0) - SET(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE 0) -ENDIF() - -#----------------------------------------------------------------------------- -# If a namespace is not specified, use "kwsys" and enable testing. -# This should be the case only when kwsys is not included inside -# another project and is being tested. -IF(NOT KWSYS_NAMESPACE) - SET(KWSYS_NAMESPACE "kwsys") - SET(KWSYS_STANDALONE 1) -ENDIF() - -#----------------------------------------------------------------------------- -# The project name is that of the specified namespace. -PROJECT(${KWSYS_NAMESPACE}) - -# Tell CMake how to follow dependencies of sources in this directory. -SET_PROPERTY(DIRECTORY - PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM - "KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>" - ) - -# Select library components. -IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) - SET(KWSYS_ENABLE_C 1) - # Enable all components. - SET(KWSYS_USE_Base64 1) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_DynamicLoader 1) - SET(KWSYS_USE_Encoding 1) - SET(KWSYS_USE_Glob 1) - SET(KWSYS_USE_MD5 1) - SET(KWSYS_USE_Process 1) - SET(KWSYS_USE_RegularExpression 1) - SET(KWSYS_USE_System 1) - SET(KWSYS_USE_SystemTools 1) - SET(KWSYS_USE_CommandLineArguments 1) - SET(KWSYS_USE_Terminal 1) - SET(KWSYS_USE_IOStream 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_String 1) - SET(KWSYS_USE_SystemInformation 1) - SET(KWSYS_USE_ConsoleBuf 1) -ENDIF() - -# Enforce component dependencies. -IF(KWSYS_USE_SystemTools) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Glob) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_SystemTools 1) - SET(KWSYS_USE_RegularExpression 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Process) - SET(KWSYS_USE_System 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_SystemInformation) - SET(KWSYS_USE_Process 1) -ENDIF() -IF(KWSYS_USE_System) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Directory) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_FStream) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_ConsoleBuf) - SET(KWSYS_USE_Encoding 1) -ENDIF() - -# Setup the large file support default. -IF(KWSYS_LFS_DISABLE) - SET(KWSYS_LFS_REQUESTED 0) -ELSE() - SET(KWSYS_LFS_REQUESTED 1) -ENDIF() - -# Specify default 8 bit encoding for Windows -IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE) - SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP) -ENDIF() - -# Enable testing if building standalone. -IF(KWSYS_STANDALONE) - INCLUDE(Dart) - MARK_AS_ADVANCED(BUILD_TESTING DART_ROOT TCL_TCLSH) - IF(BUILD_TESTING) - ENABLE_TESTING() - ENDIF() -ENDIF() - -# Include helper macros. -INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake) -INCLUDE(CheckTypeSize) - -# Do full dependency headers. -INCLUDE_REGULAR_EXPRESSION("^.*$") - -# Use new KWSYS_INSTALL_*_DIR variable names to control installation. -# Take defaults from the old names. Note that there was no old name -# for the bin dir, so we take the old lib dir name so DLLs will be -# installed in a compatible way for old code. -IF(NOT KWSYS_INSTALL_INCLUDE_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR - "${KWSYS_HEADER_INSTALL_DIR}") -ENDIF() -IF(NOT KWSYS_INSTALL_LIB_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR - "${KWSYS_LIBRARY_INSTALL_DIR}") -ENDIF() -IF(NOT KWSYS_INSTALL_BIN_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR - "${KWSYS_LIBRARY_INSTALL_DIR}") -ENDIF() - -# Setup header install rules. -SET(KWSYS_INSTALL_INCLUDE_OPTIONS) -IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) - SET(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} - ) -ENDIF() - -# Setup library install rules. -SET(KWSYS_INSTALL_LIBRARY_RULE) -IF(KWSYS_INSTALL_LIB_DIR) - IF(KWSYS_INSTALL_EXPORT_NAME) - LIST(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME}) - ENDIF() - # Install the shared library to the lib directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} - ) - # Assign the shared library to the runtime component. - IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} - ) - ENDIF() - - # Install the archive to the lib directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR} - ) - # Assign the archive to the development component. - IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} - ) - ENDIF() -ENDIF() -IF(KWSYS_INSTALL_BIN_DIR) - # Install the runtime library to the bin directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR} - ) - # Assign the runtime library to the runtime component. - IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} - ) - ENDIF() -ENDIF() - -# Do not support old KWSYS_*a_INSTALL_DIR variable names. -SET(KWSYS_HEADER_INSTALL_DIR) -SET(KWSYS_LIBRARY_INSTALL_DIR) - -# Generated source files will need this header. -STRING(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}" - KWSYS_IN_SOURCE_BUILD) -IF(NOT KWSYS_IN_SOURCE_BUILD) - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsysPrivate.h - ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE) -ENDIF() - -# Select plugin module file name convention. -IF(NOT KWSYS_DynamicLoader_PREFIX) - SET(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX}) -ENDIF() -IF(NOT KWSYS_DynamicLoader_SUFFIX) - SET(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX}) -ENDIF() - -#----------------------------------------------------------------------------- -# We require ANSI support from the C compiler. Add any needed flags. -IF(CMAKE_ANSI_CFLAGS) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}") -ENDIF() - -#----------------------------------------------------------------------------- -# Adjust compiler flags for some platforms. -IF(NOT CMAKE_COMPILER_IS_GNUCXX) - IF(CMAKE_SYSTEM MATCHES "OSF1-V.*") - STRING(REGEX MATCH "-timplicit_local" - KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}") - STRING(REGEX MATCH "-no_implicit_include" - KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}") - IF(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local") - ENDIF() - IF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include") - ENDIF() - ENDIF() - IF(CMAKE_SYSTEM MATCHES "HP-UX") - SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p") - IF(CMAKE_CXX_COMPILER_ID MATCHES "HP") - # it is known that version 3.85 fails and 6.25 works without these flags - IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4) - # use new C++ library and improved template support - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98") - ENDIF() - ENDIF() - ENDIF() -ENDIF() -IF(KWSYS_STANDALONE) - IF(CMAKE_CXX_COMPILER_ID STREQUAL SunPro) - IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03") - ELSE() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4") - ENDIF() - ENDIF() -ENDIF() - -#----------------------------------------------------------------------------- -# Configure Large File Support. -KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CSTDIO - "Checking whether header cstdio is available" DIRECT) -SET(KWSYS_LFS_AVAILABLE 0) -IF(KWSYS_LFS_REQUESTED) - # Large File Support is requested. - SET(KWSYS_LFS_REQUESTED 1) - - # Check for large file support. - SET(KWSYS_PLATFORM_CXX_TEST_DEFINES - -DKWSYS_CXX_HAS_CSTDIO=${KWSYS_CXX_HAS_CSTDIO}) - KWSYS_PLATFORM_CXX_TEST_RUN(KWSYS_LFS_WORKS - "Checking for Large File Support" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) - - IF(KWSYS_LFS_WORKS) - SET(KWSYS_LFS_AVAILABLE 1) - ENDIF() -ELSE() - # Large File Support is not requested. - SET(KWSYS_LFS_REQUESTED 0) -ENDIF() - -#----------------------------------------------------------------------------- -# Configure the standard library header wrappers based on compiler's -# capabilities and parent project's request. Enforce 0/1 as only -# possible values for configuration into Configure.hxx. - -# Check existence and uniqueness of long long and __int64. -KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_LONG_LONG - "Checking whether C++ compiler has 'long long'" DIRECT) -KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS___INT64 - "Checking whether C++ compiler has '__int64'" DIRECT) -IF(KWSYS_CXX_HAS___INT64) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_AND___INT64 - "Checking whether long and __int64 are the same type" DIRECT) - IF(KWSYS_CXX_HAS_LONG_LONG) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_LONG_AND___INT64 - "Checking whether long long and __int64 are the same type" DIRECT) - ENDIF() -ENDIF() - -# Enable the "long long" type if it is available. It is standard in -# C99 and C++03 but not in earlier standards. -IF(KWSYS_CXX_HAS_LONG_LONG) - SET(KWSYS_USE_LONG_LONG 1) -ELSE() - SET(KWSYS_USE_LONG_LONG 0) -ENDIF() - -# Enable the "__int64" type if it is available and unique. It is not -# standard. -SET(KWSYS_USE___INT64 0) -IF(KWSYS_CXX_HAS___INT64) - IF(NOT KWSYS_CXX_SAME_LONG_AND___INT64) - IF(NOT KWSYS_CXX_SAME_LONG_LONG_AND___INT64) - SET(KWSYS_USE___INT64 1) - ENDIF() - ENDIF() -ENDIF() - -IF(KWSYS_USE_Encoding) - # Look for type size helper macros. - KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING - "Checking whether wstring is available" DIRECT) -ENDIF() - -IF(KWSYS_USE_IOStream) - # Determine whether iostreams support long long. - IF(KWSYS_CXX_HAS_LONG_LONG) - KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG - "Checking if istream supports long long" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG - "Checking if ostream supports long long" DIRECT) - ELSE() - SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0) - SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0) - ENDIF() - IF(KWSYS_CXX_HAS___INT64) - KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM___INT64 - "Checking if istream supports __int64" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM___INT64 - "Checking if ostream supports __int64" DIRECT) - ELSE() - SET(KWSYS_IOS_HAS_ISTREAM___INT64 0) - SET(KWSYS_IOS_HAS_OSTREAM___INT64 0) - ENDIF() -ENDIF() - -IF(KWSYS_NAMESPACE MATCHES "^kwsys$") - SET(KWSYS_NAME_IS_KWSYS 1) -ELSE() - SET(KWSYS_NAME_IS_KWSYS 0) -ENDIF() - -# Choose default shared/static build if not specified. -IF(KWSYS_BUILD_SHARED MATCHES "^KWSYS_BUILD_SHARED$") - SET(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS}) -ENDIF() - -IF(KWSYS_BUILD_SHARED) - SET(KWSYS_BUILD_SHARED 1) - SET(KWSYS_LIBRARY_TYPE SHARED) -ELSE() - SET(KWSYS_BUILD_SHARED 0) - SET(KWSYS_LIBRARY_TYPE STATIC) -ENDIF() - -IF(NOT KWSYS_DEFINE_SYMBOL) - SET(KWSYS_DEFINE_SYMBOL ${KWSYS_NAMESPACE}_EXPORTS) -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) - 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() - IF(KWSYS_LFS_AVAILABLE AND NOT KWSYS_LFS_DISABLE) - SET(KWSYS_PLATFORM_CXX_TEST_DEFINES -DKWSYS_HAS_LFS=1) - ENDIF() - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64 - "Checking whether CXX compiler has rlimit64" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) - IF(KWSYS_CXX_HAS_RLIMIT64) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1) - ENDIF() - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOL - "Checking whether CXX compiler has atol" DIRECT) - IF(KWSYS_CXX_HAS_ATOL) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1) - ENDIF() - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOLL - "Checking whether CXX compiler has atoll" DIRECT) - IF(KWSYS_CXX_HAS_ATOLL) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1) - ENDIF() - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS__ATOI64 - "Checking whether CXX compiler has _atoi64" DIRECT) - IF(KWSYS_CXX_HAS__ATOI64) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1) - ENDIF() - IF(UNIX) - INCLUDE(CheckIncludeFileCXX) - # check for simple stack trace - # usually it's in libc but on FreeBSD - # it's in libexecinfo - FIND_LIBRARY(EXECINFO_LIB "execinfo") - MARK_AS_ADVANCED(EXECINFO_LIB) - IF (NOT EXECINFO_LIB) - SET(EXECINFO_LIB "") - ENDIF() - CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH) - IF (KWSYS_CXX_HAS_EXECINFOH) - # we have the backtrace header check if it - # can be used with this compiler - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB}) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE - "Checking whether backtrace works with this C++ compiler" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) - IF (KWSYS_CXX_HAS_BACKTRACE) - # backtrace is supported by this system and compiler. - # now check for the more advanced capabilities. - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1) - # check for symbol lookup using dladdr - CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH) - IF (KWSYS_CXX_HAS_DLFCNH) - # we have symbol lookup libraries and headers - # check if they can be used with this compiler - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS}) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR - "Checking whether dladdr works with this C++ compiler" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) - IF (KWSYS_CXX_HAS_DLADDR) - # symbol lookup is supported by this system - # and compiler. - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1) - ENDIF() - ENDIF() - # c++ demangling support - # check for cxxabi headers - CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH) - IF (KWSYS_CXX_HAS_CXXABIH) - # check if cxxabi can be used with this - # system and compiler. - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI - "Checking whether cxxabi works with this C++ compiler" DIRECT) - IF (KWSYS_CXX_HAS_CXXABI) - # c++ demangle using cxxabi is supported with - # this system and compiler - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1) - ENDIF() - ENDIF() - # basic backtrace works better with release build - # don't bother with advanced features for release - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) - ENDIF() - ENDIF() - ENDIF() - IF(BORLAND) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM - "Checking whether Borland CXX compiler supports assembler instructions" DIRECT) - IF(KWSYS_CXX_HAS_BORLAND_ASM) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM=1) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM_CPUID - "Checking whether Borland CXX compiler supports CPUID assembler instruction" DIRECT) - IF(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM_CPUID=1) - ENDIF() - ENDIF() - ENDIF() - IF(KWSYS_USE___INT64) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_USE___INT64=1) - ENDIF() - IF(KWSYS_USE_LONG_LONG) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=1) - ENDIF() - IF(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM_LONG_LONG=1) - ENDIF() - IF(KWSYS_IOS_HAS_OSTREAM___INT64) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1) - ENDIF() - IF(KWSYS_BUILD_SHARED) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1) - ENDIF() - - IF(UNIX AND NOT CYGWIN) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG - "Checking whether CXX compiler has getloadavg" DIRECT) - IF(KWSYS_CXX_HAS_GETLOADAVG) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1) - ENDIF() - ENDIF() -ENDIF() - -IF(KWSYS_USE_FStream) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H - "Checking whether 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) - SET_PROPERTY(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY - POSITION_INDEPENDENT_CODE TRUE) - TARGET_COMPILE_DEFINITIONS(${KWSYS_TARGET_OBJECT} PRIVATE - ${KWSYS_DEFINE_SYMBOL}) - 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 - $) - 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}) - 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) - 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 - $) - IF(KWSYS_INSTALL_INCLUDE_DIR) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE - $) - ENDIF() - ENDIF() - - # Create an install target for the library. - IF(KWSYS_INSTALL_LIBRARY_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_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) - SET_PROPERTY(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY - POSITION_INDEPENDENT_CODE TRUE) - TARGET_COMPILE_DEFINITIONS(${KWSYS_TARGET_C_OBJECT} PRIVATE - ${KWSYS_DEFINE_SYMBOL}) - 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 - $) - 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 - $) - IF(KWSYS_INSTALL_INCLUDE_DIR) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE - $) - 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")) - 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("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" AND - CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506") - set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8) - ENDIF() - SET_PROPERTY(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS - KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) - ENDIF() - IF(KWSYS_USE_SystemInformation) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.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}) - 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" AND - NOT (CMAKE_SYSTEM MATCHES "Linux.*ppc64le" AND - NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.1")) - # Tell IBM XL not to warn about our test infinite loop - # v13.1.1 and newer on Linux ppc64le is clang based and does not accept - # the -qsuppress option - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010") - 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() diff --git a/thirdparty/KWSys/adios2sys/CONTRIBUTING.rst b/thirdparty/KWSys/adios2sys/CONTRIBUTING.rst deleted file mode 100644 index 70a313e058..0000000000 --- a/thirdparty/KWSys/adios2sys/CONTRIBUTING.rst +++ /dev/null @@ -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 **3.8** 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 diff --git a/thirdparty/KWSys/adios2sys/CTestConfig.cmake b/thirdparty/KWSys/adios2sys/CTestConfig.cmake deleted file mode 100644 index 1339ffc2dd..0000000000 --- a/thirdparty/KWSys/adios2sys/CTestConfig.cmake +++ /dev/null @@ -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) diff --git a/thirdparty/KWSys/adios2sys/CTestCustom.cmake.in b/thirdparty/KWSys/adios2sys/CTestCustom.cmake.in deleted file mode 100644 index 760221b124..0000000000 --- a/thirdparty/KWSys/adios2sys/CTestCustom.cmake.in +++ /dev/null @@ -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 - ) diff --git a/thirdparty/KWSys/adios2sys/CommandLineArguments.cxx b/thirdparty/KWSys/adios2sys/CommandLineArguments.cxx deleted file mode 100644 index a6387eaba9..0000000000 --- a/thirdparty/KWSys/adios2sys/CommandLineArguments.cxx +++ /dev/null @@ -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 -#include -#include -#include -#include - -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) -#pragma set woff 1375 /* base class destructor not virtual */ -#endif - -#if 0 -#define CommandLineArguments_DEBUG(x) \ - 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 -{ -}; -class CommandLineArgumentsSetOfStrings : public std::set -{ -}; -class CommandLineArgumentsMapOfStrucs - : public std::map -{ -}; - -class CommandLineArgumentsInternal -{ -public: - CommandLineArgumentsInternal() - { - this->UnknownArgumentCallback = KWSYS_NULLPTR; - this->ClientData = KWSYS_NULLPTR; - this->LastArgument = 0; - } - - typedef CommandLineArgumentsVectorOfStrings VectorOfStrings; - typedef CommandLineArgumentsMapOfStrucs CallbacksMap; - typedef kwsys::String String; - typedef CommandLineArgumentsSetOfStrings SetOfStrings; - - VectorOfStrings Argv; - String Argv0; - CallbacksMap Callbacks; - - CommandLineArguments::ErrorCallbackType UnknownArgumentCallback; - void* ClientData; - - VectorOfStrings::size_type LastArgument; - - VectorOfStrings UnusedArguments; -}; - -CommandLineArguments::CommandLineArguments() -{ - this->Internals = new CommandLineArguments::Internal; - this->Help = ""; - this->LineLength = 80; - this->StoreUnusedArgumentsFlag = false; -} - -CommandLineArguments::~CommandLineArguments() -{ - delete this->Internals; -} - -void CommandLineArguments::Initialize(int argc, const char* const argv[]) -{ - int cc; - - this->Initialize(); - this->Internals->Argv0 = argv[0]; - for (cc = 1; cc < argc; cc++) { - this->ProcessArgument(argv[cc]); - } -} - -void CommandLineArguments::Initialize(int argc, char* argv[]) -{ - this->Initialize(argc, static_cast(argv)); -} - -void CommandLineArguments::Initialize() -{ - this->Internals->Argv.clear(); - this->Internals->LastArgument = 0; -} - -void CommandLineArguments::ProcessArgument(const char* arg) -{ - this->Internals->Argv.push_back(arg); -} - -bool CommandLineArguments::GetMatchedArguments( - std::vector* 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::size_type cc; - std::vector 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, KWSYS_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 = KWSYS_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 = KWSYS_NULLPTR; - s.CallData = KWSYS_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) -CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector) -CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, std::vector) -CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, std::vector) -CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING, - std::vector) -#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 KWSYS_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(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 - 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(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 = KWSYS_NULLPTR; - *variable = static_cast(strtol(value.c_str(), &res, 10)); - // if ( res && *res ) - // { - // Can handle non-int - // } -} - -void CommandLineArguments::PopulateVariable(double* variable, - const std::string& value) -{ - char* res = KWSYS_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* 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* variable, - const std::string& value) -{ - char* res = KWSYS_NULLPTR; - variable->push_back(static_cast(strtol(value.c_str(), &res, 10))); - // if ( res && *res ) - // { - // Can handle non-int - // } -} - -void CommandLineArguments::PopulateVariable(std::vector* variable, - const std::string& value) -{ - char* res = KWSYS_NULLPTR; - variable->push_back(strtod(value.c_str(), &res)); - // if ( res && *res ) - // { - // Can handle non-int - // } -} - -void CommandLineArguments::PopulateVariable(std::vector* 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* 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(cs->Variable), var); - break; - case CommandLineArguments::DOUBLE_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::STRING_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::STL_STRING_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::BOOL_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::VECTOR_BOOL_TYPE: - this->PopulateVariable(static_cast*>(cs->Variable), - var); - break; - case CommandLineArguments::VECTOR_INT_TYPE: - this->PopulateVariable(static_cast*>(cs->Variable), - var); - break; - case CommandLineArguments::VECTOR_DOUBLE_TYPE: - this->PopulateVariable(static_cast*>(cs->Variable), - var); - break; - case CommandLineArguments::VECTOR_STRING_TYPE: - this->PopulateVariable(static_cast*>(cs->Variable), - var); - break; - case CommandLineArguments::VECTOR_STL_STRING_TYPE: - this->PopulateVariable( - static_cast*>(cs->Variable), var); - break; - default: - std::cerr << "Got unknown variable type: \"" << cs->VariableType - << "\"" << std::endl; - this->Internals->LastArgument--; - return 0; - } - } - return 1; -} - -} // namespace KWSYS_NAMESPACE diff --git a/thirdparty/KWSys/adios2sys/CommandLineArguments.hxx.in b/thirdparty/KWSys/adios2sys/CommandLineArguments.hxx.in deleted file mode 100644 index 31115e51fb..0000000000 --- a/thirdparty/KWSys/adios2sys/CommandLineArguments.hxx.in +++ /dev/null @@ -1,267 +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 -#include - -namespace @KWSYS_NAMESPACE@ { - -class CommandLineArgumentsInternal; -struct CommandLineArgumentsCallbackStructure; - -/** \class CommandLineArguments - * \brief Command line arguments processing code. - * - * Find specified arguments with optional options and execute specified methods - * or set given variables. - * - * The two interfaces it knows are callback based and variable based. For - * callback based, you have to register callback for particular argument using - * AddCallback method. When that argument is passed, the callback will be - * called with argument, value, and call data. For boolean (NO_ARGUMENT) - * arguments, the value is "1". If the callback returns 0 the argument parsing - * will stop with an error. - * - * For the variable interface you associate variable with each argument. When - * the argument is specified, the variable is set to the specified value casted - * to the appropriate type. For boolean (NO_ARGUMENT), the value is "1". - * - * Both interfaces can be used at the same time. - * - * Possible argument types are: - * NO_ARGUMENT - The argument takes no value : --A - * CONCAT_ARGUMENT - The argument takes value after no space : --Aval - * SPACE_ARGUMENT - The argument takes value after space : --A val - * EQUAL_ARGUMENT - The argument takes value after equal : --A=val - * MULTI_ARGUMENT - The argument takes values after space : --A val1 val2 - * val3 ... - * - * Example use: - * - * kwsys::CommandLineArguments arg; - * arg.Initialize(argc, argv); - * typedef kwsys::CommandLineArguments argT; - * arg.AddArgument("--something", argT::EQUAL_ARGUMENT, &some_variable, - * "This is help string for --something"); - * if ( !arg.Parse() ) - * { - * std::cerr << "Problem parsing arguments" << std::endl; - * res = 1; - * } - * - */ - -class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments -{ -public: - CommandLineArguments(); - ~CommandLineArguments(); - - /** - * Various argument types. - */ - enum ArgumentTypeEnum - { - NO_ARGUMENT, - CONCAT_ARGUMENT, - SPACE_ARGUMENT, - EQUAL_ARGUMENT, - MULTI_ARGUMENT - }; - - /** - * Various variable types. When using the variable interface, this specifies - * what type the variable is. - */ - enum VariableTypeEnum - { - NO_VARIABLE_TYPE = 0, // The variable is not specified - INT_TYPE, // The variable is integer (int) - BOOL_TYPE, // The variable is boolean (bool) - DOUBLE_TYPE, // The variable is float (double) - STRING_TYPE, // The variable is string (char*) - STL_STRING_TYPE, // The variable is string (char*) - VECTOR_INT_TYPE, // The variable is integer (int) - VECTOR_BOOL_TYPE, // The variable is boolean (bool) - VECTOR_DOUBLE_TYPE, // The variable is float (double) - VECTOR_STRING_TYPE, // The variable is string (char*) - VECTOR_STL_STRING_TYPE, // The variable is string (char*) - LAST_VARIABLE_TYPE - }; - - /** - * Prototypes for callbacks for callback interface. - */ - typedef int (*CallbackType)(const char* argument, const char* value, - void* call_data); - typedef int (*ErrorCallbackType)(const char* argument, void* client_data); - - /** - * Initialize internal data structures. This should be called before parsing. - */ - void Initialize(int argc, const char* const argv[]); - void Initialize(int argc, char* argv[]); - - /** - * Initialize internal data structure and pass arguments one by one. This is - * convenience method for use from scripting languages where argc and argv - * are not available. - */ - void Initialize(); - void ProcessArgument(const char* arg); - - /** - * This method will parse arguments and call appropriate methods. - */ - int Parse(); - - /** - * This method will add a callback for a specific argument. The arguments to - * it are argument, argument type, callback method, and call data. The - * argument help specifies the help string used with this option. The - * callback and call_data can be skipped. - */ - void AddCallback(const char* argument, ArgumentTypeEnum type, - CallbackType callback, void* call_data, const char* help); - - /** - * Add handler for argument which is going to set the variable to the - * specified value. If the argument is specified, the option is casted to the - * appropriate type. - */ - void AddArgument(const char* argument, ArgumentTypeEnum type, bool* variable, - const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, int* variable, - const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - double* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - char** variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::string* variable, const char* help); - - /** - * Add handler for argument which is going to set the variable to the - * specified value. If the argument is specified, the option is casted to the - * appropriate type. This will handle the multi argument values. - */ - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - - /** - * Add handler for boolean argument. The argument does not take any option - * and if it is specified, the value of the variable is true/1, otherwise it - * is false/0. - */ - void AddBooleanArgument(const char* argument, bool* variable, - const char* help); - void AddBooleanArgument(const char* argument, int* variable, - const char* help); - void AddBooleanArgument(const char* argument, double* variable, - const char* help); - void AddBooleanArgument(const char* argument, char** variable, - const char* help); - void AddBooleanArgument(const char* argument, 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* 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* variable, const std::string& value); - void PopulateVariable(std::vector* variable, const std::string& value); - void PopulateVariable(std::vector* variable, - const std::string& value); - void PopulateVariable(std::vector* variable, - const std::string& value); - void PopulateVariable(std::vector* variable, - const std::string& value); - - typedef CommandLineArgumentsInternal Internal; - Internal* Internals; - std::string Help; - - unsigned int LineLength; - - bool StoreUnusedArgumentsFlag; -}; - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/Configure.h.in b/thirdparty/KWSys/adios2sys/Configure.h.in deleted file mode 100644 index 1b4b3bf3b9..0000000000 --- a/thirdparty/KWSys/adios2sys/Configure.h.in +++ /dev/null @@ -1,124 +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@ - -/* Whether Large File Support is requested. */ -#define @KWSYS_NAMESPACE@_LFS_REQUESTED @KWSYS_LFS_REQUESTED@ - -/* Whether Large File Support is available. */ -#if @KWSYS_NAMESPACE@_LFS_REQUESTED -#define @KWSYS_NAMESPACE@_LFS_AVAILABLE @KWSYS_LFS_AVAILABLE@ -#endif - -/* Setup Large File Support if requested. */ -#if @KWSYS_NAMESPACE@_LFS_REQUESTED -/* Since LFS is requested this header must be included before system - headers whether or not LFS is available. */ -#if 0 && (defined(_SYS_TYPES_H) || defined(_SYS_TYPES_INCLUDED)) -#error "@KWSYS_NAMESPACE@/Configure.h must be included before sys/types.h" -#endif -/* Enable the large file API if it is available. */ -#if @KWSYS_NAMESPACE@_LFS_AVAILABLE && \ - !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINES) -#if !defined(_LARGEFILE_SOURCE) && \ - !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE_SOURCE) -#define _LARGEFILE_SOURCE -#endif -#if !defined(_LARGEFILE64_SOURCE) && \ - !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE64_SOURCE) -#define _LARGEFILE64_SOURCE -#endif -#if !defined(_LARGE_FILES) && \ - !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGE_FILES) -#define _LARGE_FILES -#endif -#if !defined(_FILE_OFFSET_BITS) && \ - !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_FILE_OFFSET_BITS) -#define _FILE_OFFSET_BITS 64 -#endif -#endif -#endif - -/* Setup the export macro. */ -#if @KWSYS_BUILD_SHARED@ -#if defined(_WIN32) || defined(__CYGWIN__) -#if defined(@KWSYS_DEFINE_SYMBOL@) -#define @KWSYS_NAMESPACE@_EXPORT __declspec(dllexport) -#else -#define @KWSYS_NAMESPACE@_EXPORT __declspec(dllimport) -#endif -#elif __GNUC__ >= 4 -#define @KWSYS_NAMESPACE@_EXPORT __attribute__((visibility("default"))) -#else -#define @KWSYS_NAMESPACE@_EXPORT -#endif -#else -#define @KWSYS_NAMESPACE@_EXPORT -#endif - -/* Enable warnings that are off by default but are useful. */ -#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_ENABLE) -#if defined(_MSC_VER) -#pragma warning(default : 4263) /* no override, call convention differs */ -#endif -#endif - -/* Disable warnings that are on by default but occur in valid code. */ -#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE) -#if defined(_MSC_VER) -#pragma warning(disable : 4097) /* typedef is synonym for class */ -#pragma warning(disable : 4127) /* conditional expression is constant */ -#pragma warning(disable : 4244) /* possible loss in conversion */ -#pragma warning(disable : 4251) /* missing DLL-interface */ -#pragma warning(disable : 4305) /* truncation from type1 to type2 */ -#pragma warning(disable : 4309) /* truncation of constant value */ -#pragma warning(disable : 4514) /* unreferenced inline function */ -#pragma warning(disable : 4706) /* assignment in conditional expression */ -#pragma warning(disable : 4710) /* function not inlined */ -#pragma warning(disable : 4786) /* identifier truncated in debug info */ -#endif -#if defined(__BORLANDC__) && !defined(__cplusplus) -/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an - unused parameter using "(param)" syntax (i.e. no cast to void). */ -#pragma warn - 8019 -#endif -#endif - -/* MSVC 6.0 in release mode will warn about code it produces with its - optimizer. Disable the warnings specifically for this - configuration. Real warnings will be revealed by a debug build or - by other compilers. */ -#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE_BOGUS) -#if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG) -#pragma warning(disable : 4701) /* Variable may be used uninitialized. */ -#pragma warning(disable : 4702) /* Unreachable code. */ -#endif -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/Configure.hxx.in b/thirdparty/KWSys/adios2sys/Configure.hxx.in deleted file mode 100644 index 05afc7d12d..0000000000 --- a/thirdparty/KWSys/adios2sys/Configure.hxx.in +++ /dev/null @@ -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@_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 is available. */ -#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \ - @KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@ - -#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(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_NULLPTR @KWSYS_NAMESPACE@_NULLPTR -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/ConsoleBuf.hxx.in b/thirdparty/KWSys/adios2sys/ConsoleBuf.hxx.in deleted file mode 100644 index cf68146c4b..0000000000 --- a/thirdparty/KWSys/adios2sys/ConsoleBuf.hxx.in +++ /dev/null @@ -1,396 +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 -#include -#include -#include -#include -#include - -#if defined(_WIN32) -#include -#if __cplusplus >= 201103L -#include -#endif -#endif - -namespace @KWSYS_NAMESPACE@ { -#if defined(_WIN32) - -template > -class BasicConsoleBuf : public std::basic_streambuf -{ -public: - typedef typename Traits::int_type int_type; - typedef typename Traits::char_type char_type; - - class Manager - { - public: - Manager(std::basic_ios& ios, const bool err = false) - : m_consolebuf(0) - { - m_ios = &ios; - try { - m_consolebuf = new BasicConsoleBuf(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* 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* m_ios; - std::basic_streambuf* m_streambuf; - BasicConsoleBuf* m_consolebuf; - }; - - BasicConsoleBuf(const bool err = false) - : flush_on_newline(true) - , input_pipe_codepage(0) - , output_pipe_codepage(0) - , input_file_codepage(CP_UTF8) - , output_file_codepage(CP_UTF8) - , m_consolesCodepage(0) - { - m_hInput = ::GetStdHandle(STD_INPUT_HANDLE); - checkHandle(true, "STD_INPUT_HANDLE"); - if (!setActiveInputCodepage()) { - throw std::runtime_error("setActiveInputCodepage failed!"); - } - m_hOutput = err ? ::GetStdHandle(STD_ERROR_HANDLE) - : ::GetStdHandle(STD_OUTPUT_HANDLE); - checkHandle(false, err ? "STD_ERROR_HANDLE" : "STD_OUTPUT_HANDLE"); - if (!setActiveOutputCodepage()) { - throw std::runtime_error("setActiveOutputCodepage failed!"); - } - _setg(); - _setp(); - } - - ~BasicConsoleBuf() throw() { sync(); } - - bool activateCodepageChange() - { - return setActiveInputCodepage() && setActiveOutputCodepage(); - } - -protected: - virtual int sync() - { - bool success = true; - if (m_hInput && m_isConsoleInput && - ::FlushConsoleInputBuffer(m_hInput) == 0) { - success = false; - } - if (m_hOutput && !m_obuffer.empty()) { - const std::wstring wbuffer = getBuffer(m_obuffer); - if (m_isConsoleOutput) { - DWORD charsWritten; - success = - ::WriteConsoleW(m_hOutput, wbuffer.c_str(), (DWORD)wbuffer.size(), - &charsWritten, NULL) == 0 - ? false - : true; - } else { - DWORD bytesWritten; - std::string buffer; - success = encodeOutputBuffer(wbuffer, buffer); - if (success) { - success = ::WriteFile(m_hOutput, buffer.c_str(), - (DWORD)buffer.size(), &bytesWritten, NULL) == 0 - ? false - : true; - } - } - } - m_ibuffer.clear(); - m_obuffer.clear(); - _setg(); - _setp(); - return success ? 0 : -1; - } - - virtual int_type underflow() - { - if (this->gptr() >= this->egptr()) { - if (!m_hInput) { - _setg(true); - return Traits::eof(); - } - if (m_isConsoleInput) { - // ReadConsole doesn't tell if there's more input available - // don't support reading more characters than this - wchar_t wbuffer[8192]; - DWORD charsRead; - if (ReadConsoleW(m_hInput, wbuffer, - (sizeof(wbuffer) / sizeof(wbuffer[0])), &charsRead, - NULL) == 0 || - charsRead == 0) { - _setg(true); - return Traits::eof(); - } - setBuffer(std::wstring(wbuffer, charsRead), m_ibuffer); - } else { - std::wstring wbuffer; - std::string strbuffer; - DWORD bytesRead; - LARGE_INTEGER size; - if (GetFileSizeEx(m_hInput, &size) == 0) { - _setg(true); - return Traits::eof(); - } - char* buffer = new char[size.LowPart]; - while (ReadFile(m_hInput, buffer, size.LowPart, &bytesRead, NULL) == - 0) { - if (GetLastError() == ERROR_MORE_DATA) { - strbuffer += std::string(buffer, bytesRead); - continue; - } - _setg(true); - delete[] buffer; - return Traits::eof(); - } - if (bytesRead > 0) { - strbuffer += std::string(buffer, bytesRead); - } - delete[] buffer; - if (!decodeInputBuffer(strbuffer, wbuffer)) { - _setg(true); - return Traits::eof(); - } - setBuffer(wbuffer, m_ibuffer); - } - _setg(); - } - return Traits::to_int_type(*this->gptr()); - } - - virtual int_type overflow(int_type ch = Traits::eof()) - { - if (!Traits::eq_int_type(ch, Traits::eof())) { - char_type chr = Traits::to_char_type(ch); - m_obuffer += chr; - if ((flush_on_newline && Traits::eq(chr, '\n')) || - Traits::eq_int_type(ch, 0x00)) { - sync(); - } - return ch; - } - sync(); - return Traits::eof(); - } - -public: - bool flush_on_newline; - UINT input_pipe_codepage; - UINT output_pipe_codepage; - UINT input_file_codepage; - UINT output_file_codepage; - -private: - HANDLE m_hInput; - HANDLE m_hOutput; - std::basic_string m_ibuffer; - std::basic_string 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(), NULL, 0, NULL, NULL); - char* buf = new char[length]; - const bool success = - WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(), - (int)wbuffer.size(), buf, length, NULL, NULL) > 0 - ? true - : false; - buffer = std::string(buf, length); - delete[] buf; - return success; - } - bool decodeInputBuffer(const std::string buffer, std::wstring& wbuffer) - { - 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(MultiByteToWideChar( - actualCodepage, 0, data, static_cast(length), NULL, 0)); - wchar_t* wbuf = new wchar_t[wlength]; - const bool success = - MultiByteToWideChar(actualCodepage, 0, data, static_cast(length), - wbuf, static_cast(wlength)) > 0 - ? true - : false; - wbuffer = std::wstring(wbuf, wlength); - delete[] wbuf; - return success; - } - std::wstring getBuffer(const std::basic_string buffer) - { - return Encoding::ToWide(buffer); - } - std::wstring getBuffer(const std::basic_string buffer) - { - return buffer; - } - void setBuffer(const std::wstring wbuffer, std::basic_string& target) - { - target = Encoding::ToNarrow(wbuffer); - } - void setBuffer(const std::wstring wbuffer, - std::basic_string& target) - { - target = wbuffer; - } - -}; // BasicConsoleBuf class - -typedef BasicConsoleBuf ConsoleBuf; -typedef BasicConsoleBuf WConsoleBuf; - -#endif -} // KWSYS_NAMESPACE - -#endif diff --git a/thirdparty/KWSys/adios2sys/Copyright.txt b/thirdparty/KWSys/adios2sys/Copyright.txt deleted file mode 100644 index 33d7fb4726..0000000000 --- a/thirdparty/KWSys/adios2sys/Copyright.txt +++ /dev/null @@ -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 - -See version control history for details of individual contributions. diff --git a/thirdparty/KWSys/adios2sys/Directory.cxx b/thirdparty/KWSys/adios2sys/Directory.cxx deleted file mode 100644 index a84be11861..0000000000 --- a/thirdparty/KWSys/adios2sys/Directory.cxx +++ /dev/null @@ -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 -#include - -namespace KWSYS_NAMESPACE { - -class DirectoryInternals -{ -public: - // Array of Files - std::vector 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(this->Internal->Files.size()); -} - -const char* Directory::GetFile(unsigned long dindex) const -{ - if (dindex >= this->Internal->Files.size()) { - return KWSYS_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 - -#include -#include -#include -#include -#include -#include -#include -#include - -// Wide function names can vary depending on compiler: -#ifdef __BORLANDC__ -#define _wfindfirst_func __wfindfirst -#define _wfindnext_func __wfindnext -#else -#define _wfindfirst_func _wfindfirst -#define _wfindnext_func _wfindnext -#endif - -namespace KWSYS_NAMESPACE { - -bool Directory::Load(const std::string& name) -{ - this->Clear(); -#if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) - // Older Visual C++ and Embarcadero compilers. - long srchHandle; -#else // Newer Visual C++ - intptr_t srchHandle; -#endif - char* buf; - size_t n = name.size(); - if (*name.rbegin() == '/' || *name.rbegin() == '\\') { - buf = new char[n + 1 + 1]; - sprintf(buf, "%s*", name.c_str()); - } else { - // Make sure the slashes in the wildcard suffix are consistent with the - // rest of the path - buf = new char[n + 2 + 1]; - if (name.find('\\') != 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.rbegin() == '/') { - buf = new char[n + 1 + 1]; - sprintf(buf, "%s*", name.c_str()); - } else { - buf = new char[n + 2 + 1]; - sprintf(buf, "%s/*", name.c_str()); - } - struct _wfinddata_t data; // data of current file - - // Now put them into the file array - srchHandle = - _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data); - delete[] buf; - - if (srchHandle == -1) { - return 0; - } - - // Loop through names - unsigned long count = 0; - do { - count++; - } while (_wfindnext_func(srchHandle, &data) != -1); - _findclose(srchHandle); - return count; -} - -} // namespace KWSYS_NAMESPACE - -#else - -// Now the POSIX style directory access - -#include - -#include - -// PGI with glibc has trouble with dirent and large file support: -// http://www.pgroup.com/userforum/viewtopic.php? -// p=1992&sid=f16167f51964f1a68fe5041b8eb213b6 -// Work around the problem by mapping dirent the same way as readdir. -#if defined(__PGI) && defined(__GLIBC__) -#define kwsys_dirent_readdir dirent -#define kwsys_dirent_readdir64 dirent64 -#define kwsys_dirent kwsys_dirent_lookup(readdir) -#define kwsys_dirent_lookup(x) kwsys_dirent_lookup_delay(x) -#define kwsys_dirent_lookup_delay(x) kwsys_dirent_##x -#else -#define kwsys_dirent dirent -#endif - -namespace KWSYS_NAMESPACE { - -bool Directory::Load(const std::string& name) -{ - this->Clear(); - - DIR* dir = opendir(name.c_str()); - - if (!dir) { - return 0; - } - - for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { - this->Internal->Files.push_back(d->d_name); - } - this->Internal->Path = name; - closedir(dir); - return 1; -} - -unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) -{ - DIR* dir = opendir(name.c_str()); - - if (!dir) { - return 0; - } - - unsigned long count = 0; - for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { - count++; - } - closedir(dir); - return count; -} - -} // namespace KWSYS_NAMESPACE - -#endif diff --git a/thirdparty/KWSys/adios2sys/Directory.hxx.in b/thirdparty/KWSys/adios2sys/Directory.hxx.in deleted file mode 100644 index ad8c51b86e..0000000000 --- a/thirdparty/KWSys/adios2sys/Directory.hxx.in +++ /dev/null @@ -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 - -namespace @KWSYS_NAMESPACE@ { - -class DirectoryInternals; - -/** \class Directory - * \brief Portable directory/filename traversal. - * - * Directory provides a portable way of finding the names of the files - * in a system directory. - * - * Directory currently works with Windows and Unix operating systems. - */ -class @KWSYS_NAMESPACE@_EXPORT Directory -{ -public: - Directory(); - ~Directory(); - - /** - * Load the specified directory and load the names of the files - * in that directory. 0 is returned if the directory can not be - * opened, 1 if it is opened. - */ - bool Load(const std::string&); - - /** - * Return the number of files in the current directory. - */ - unsigned long GetNumberOfFiles() const; - - /** - * Return the number of files in the specified directory. - * A higher performance static method. - */ - static unsigned long GetNumberOfFilesInDirectory(const std::string&); - - /** - * Return the file at the given index, the indexing is 0 based - */ - const char* GetFile(unsigned long) const; - - /** - * Return the path to Open'ed directory - */ - const char* GetPath() const; - - /** - * Clear the internal structure. Used internally at beginning of Load(...) - * to clear the cache. - */ - void Clear(); - -private: - // Private implementation details. - DirectoryInternals* Internal; - - Directory(const Directory&); // Not implemented. - void operator=(const Directory&); // Not implemented. -}; // End Class: Directory - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/DynamicLoader.cxx b/thirdparty/KWSys/adios2sys/DynamicLoader.cxx deleted file mode 100644 index 9b7d9bfc76..0000000000 --- a/thirdparty/KWSys/adios2sys/DynamicLoader.cxx +++ /dev/null @@ -1,441 +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) - -#include KWSYS_HEADER(Configure.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -#include "Configure.hxx.in" -#include "DynamicLoader.hxx.in" -#endif - -// This file actually contains several different implementations: -// * NOOP for environments without dynamic libs -// * HP machines which uses shl_load -// * Mac OS X 10.2.x and earlier which uses NSLinkModule -// * Windows which uses LoadLibrary -// * BeOS / Haiku -// * FreeMiNT for Atari -// * Default implementation for *NIX systems (including Mac OS X 10.3 and -// later) which use dlopen -// -// Each part of the ifdef contains a complete implementation for -// the static methods of DynamicLoader. - -#if !KWSYS_SUPPORTS_SHARED_LIBS -// Implementation for environments without dynamic libs -#include // for strerror() - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - return 0; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (!lib) { - return 0; - } - - return 1; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - return 0; -} - -const char* DynamicLoader::LastError() -{ - return "General error"; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(__hpux) -// Implementation for HPUX machines -#include -#include - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L); -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (!lib) { - return 0; - } - return !shl_unload(lib); -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - void* addr; - int status; - - /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default) - * TYPE_DATA Look for a symbol in the data segment (for example, - * variables). - * TYPE_UNDEFINED Look for any symbol. - */ - status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr); - void* result = (status < 0) ? (void*)0 : addr; - - // Hack to cast pointer-to-data to pointer-to-function. - return *reinterpret_cast(&result); -} - -const char* DynamicLoader::LastError() -{ - // TODO: Need implementation with errno/strerror - /* If successful, shl_findsym returns an integer (int) value zero. If - * shl_findsym cannot find sym, it returns -1 and sets errno to zero. - * If any other errors occur, shl_findsym returns -1 and sets errno to one - * of these values (defined in ): - * ENOEXEC - * A format error was detected in the specified library. - * ENOSYM - * A symbol on which sym depends could not be found. - * EINVAL - * The specified handle is invalid. - */ - - if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) { - return strerror(errno); - } - // else - return 0; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030) -// Implementation for Mac OS X 10.2.x and earlier -#include -#include // for strlen - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - NSObjectFileImageReturnCode rc; - NSObjectFileImage image = 0; - - rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image); - // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file - if (rc != NSObjectFileImageSuccess) { - return 0; - } - NSModule handle = - NSLinkModule(image, libname.c_str(), NSLINKMODULE_OPTION_BINDNOW | - NSLINKMODULE_OPTION_RETURN_ON_ERROR); - NSDestroyObjectFileImage(image); - return handle; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - // NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED - // With this option the memory for the module is not deallocated - // allowing pointers into the module to still be valid. - // You should use this option instead if your code experience some problems - // reported against Panther 10.3.9 (fixed in Tiger 10.4.2 and up) - bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE); - return success; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - void* result = 0; - // Need to prepend symbols with '_' on Apple-gcc compilers - 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(&result); -} - -const char* DynamicLoader::LastError() -{ - return 0; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(_WIN32) && !defined(__CYGWIN__) -// Implementation for Windows win32 code but not cygwin -#include - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - DynamicLoader::LibraryHandle lh; - int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0); - wchar_t* wchars = new wchar_t[length + 1]; - wchars[0] = '\0'; - MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length); - lh = LoadLibraryW(wchars); - delete[] wchars; - return lh; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - return (int)FreeLibrary(lib); -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - // TODO: The calling convention affects the name of the symbol. We - // should have a tool to help get the symbol with the desired - // calling convention. Currently we assume cdecl. - // - // Borland: - // __cdecl = "_func" (default) - // __fastcall = "@_func" - // __stdcall = "func" - // - // Watcom: - // __cdecl = "_func" - // __fastcall = "@_func@X" - // __stdcall = "_func@X" - // __watcall = "func_" (default) - // - // MSVC: - // __cdecl = "func" (default) - // __fastcall = "@_func@X" - // __stdcall = "_func@X" - // - // Note that the "@X" part of the name above is the total size (in - // bytes) of the arguments on the stack. - void* result; -#if defined(__BORLANDC__) || defined(__WATCOMC__) - // Need to prepend symbols with '_' - 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(&result); -#endif -} - -const char* DynamicLoader::LastError() -{ - LPVOID lpMsgBuf = NULL; - - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR)&lpMsgBuf, 0, NULL); - - if (!lpMsgBuf) { - return NULL; - } - - static char* str = 0; - delete[] str; - str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf); - // Free the buffer. - LocalFree(lpMsgBuf); - return str; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(__BEOS__) -// Implementation for BeOS / Haiku -#include // for strerror() - -#include -#include - -namespace KWSYS_NAMESPACE { - -static image_id last_dynamic_err = B_OK; - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - // image_id's are integers, errors are negative. Add one just in case we - // get a valid image_id of zero (is that even possible?). - image_id rc = load_add_on(libname.c_str()); - if (rc < 0) { - last_dynamic_err = rc; - return 0; - } - - return rc + 1; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (!lib) { - last_dynamic_err = B_BAD_VALUE; - return 0; - } else { - // The function dlclose() returns 0 on success, and non-zero on error. - status_t rc = unload_add_on(lib - 1); - if (rc != B_OK) { - last_dynamic_err = rc; - return 0; - } - } - - return 1; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - // Hack to cast pointer-to-data to pointer-to-function. - union - { - void* pvoid; - DynamicLoader::SymbolPointer psym; - } result; - - result.psym = NULL; - - if (!lib) { - last_dynamic_err = B_BAD_VALUE; - } else { - // !!! FIXME: BeOS can do function-only lookups...does this ever - // !!! FIXME: actually _want_ a data symbol lookup, or was this union - // !!! FIXME: a leftover of dlsym()? (s/ANY/TEXT for functions only). - status_t rc = - get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid); - if (rc != B_OK) { - last_dynamic_err = rc; - result.psym = NULL; - } - } - return result.psym; -} - -const char* DynamicLoader::LastError() -{ - const char* retval = strerror(last_dynamic_err); - last_dynamic_err = B_OK; - return retval; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(__MINT__) -// Implementation for FreeMiNT on Atari -#define _GNU_SOURCE /* for program_invocation_name */ -#include -#include -#include -#include - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - char* name = (char*)calloc(1, libname.size() + 1); - dld_init(program_invocation_name); - strncpy(name, libname.c_str(), libname.size()); - dld_link(libname.c_str()); - return (void*)name; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - dld_unlink_by_file((char*)lib, 0); - free(lib); - return 0; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - // Hack to cast pointer-to-data to pointer-to-function. - union - { - void* pvoid; - DynamicLoader::SymbolPointer psym; - } result; - result.pvoid = dld_get_symbol(sym.c_str()); - return result.psym; -} - -const char* DynamicLoader::LastError() -{ - return dld_strerror(dld_errno); -} - -} // namespace KWSYS_NAMESPACE - -#else -// Default implementation for *NIX systems (including Mac OS X 10.3 and -// later) which use dlopen -#include - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - return dlopen(libname.c_str(), RTLD_LAZY); -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (lib) { - // The function dlclose() returns 0 on success, and non-zero on error. - return !dlclose(lib); - } - // else - return 0; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - // Hack to cast pointer-to-data to pointer-to-function. - union - { - void* pvoid; - DynamicLoader::SymbolPointer psym; - } result; - result.pvoid = dlsym(lib, sym.c_str()); - return result.psym; -} - -const char* DynamicLoader::LastError() -{ - return dlerror(); -} - -} // namespace KWSYS_NAMESPACE -#endif diff --git a/thirdparty/KWSys/adios2sys/DynamicLoader.hxx.in b/thirdparty/KWSys/adios2sys/DynamicLoader.hxx.in deleted file mode 100644 index dc3469266a..0000000000 --- a/thirdparty/KWSys/adios2sys/DynamicLoader.hxx.in +++ /dev/null @@ -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. */ -#ifndef @KWSYS_NAMESPACE@_DynamicLoader_hxx -#define @KWSYS_NAMESPACE@_DynamicLoader_hxx - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include - -#if defined(__hpux) -#include -#elif defined(_WIN32) && !defined(__CYGWIN__) -#include -#elif defined(__APPLE__) -#include -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 -#include -#endif -#elif defined(__BEOS__) -#include -#endif - -namespace @KWSYS_NAMESPACE@ { -/** \class DynamicLoader - * \brief Portable loading of dynamic libraries or dll's. - * - * DynamicLoader provides a portable interface to loading dynamic - * libraries or dll's into a process. - * - * Directory currently works with Windows, Apple, HP-UX and Unix (POSIX) - * operating systems - * - * \warning dlopen on *nix system works the following way: - * If filename contains a slash ("/"), then it is interpreted as a (relative - * or absolute) pathname. Otherwise, the dynamic linker searches for the - * library as follows : see ld.so(8) for further details): - * Whereas this distinction does not exist on Win32. Therefore ideally you - * should be doing full path to 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)(); - - /** Load a dynamic library into the current process. - * The returned LibraryHandle can be used to access the symbols in the - * library. */ - static LibraryHandle OpenLibrary(const std::string&); - - /** Attempt to detach a dynamic library from the - * process. A value of true is returned if it is 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 diff --git a/thirdparty/KWSys/adios2sys/Encoding.h.in b/thirdparty/KWSys/adios2sys/Encoding.h.in deleted file mode 100644 index 7b6ed10f8b..0000000000 --- a/thirdparty/KWSys/adios2sys/Encoding.h.in +++ /dev/null @@ -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 - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -#define kwsys_ns(x) @KWSYS_NAMESPACE@##x -#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#define kwsysEncoding kwsys_ns(Encoding) -#define kwsysEncoding_mbstowcs kwsys_ns(Encoding_mbstowcs) -#define kwsysEncoding_DupToWide kwsys_ns(Encoding_DupToWide) -#define kwsysEncoding_wcstombs kwsys_ns(Encoding_wcstombs) -#define kwsysEncoding_DupToNarrow kwsys_ns(Encoding_DupToNarrow) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/* Convert a narrow string to a wide string. - On Windows, UTF-8 is assumed, and on other platforms, - the current locale is assumed. - */ -kwsysEXPORT size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* src, - size_t n); - -/* Convert a narrow string to a wide string. - This can return NULL if the conversion fails. */ -kwsysEXPORT wchar_t* kwsysEncoding_DupToWide(const char* src); - -/* Convert a wide string to a narrow string. - On Windows, UTF-8 is assumed, and on other platforms, - the current locale is assumed. */ -kwsysEXPORT size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* src, - size_t n); - -/* Convert a wide string to a narrow string. - This can return NULL if the conversion fails. */ -kwsysEXPORT char* kwsysEncoding_DupToNarrow(const wchar_t* str); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -#undef kwsys_ns -#undef kwsysEXPORT -#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#undef kwsysEncoding -#undef kwsysEncoding_mbstowcs -#undef kwsysEncoding_DupToWide -#undef kwsysEncoding_wcstombs -#undef kwsysEncoding_DupToNarrow -#endif -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/Encoding.hxx.in b/thirdparty/KWSys/adios2sys/Encoding.hxx.in deleted file mode 100644 index 09691fd3f4..0000000000 --- a/thirdparty/KWSys/adios2sys/Encoding.hxx.in +++ /dev/null @@ -1,78 +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 -#include - -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 argv_; - }; - -/** - * Convert between char and wchar_t - */ - -#if @KWSYS_NAMESPACE@_STL_HAS_WSTRING - - // Convert a narrow string to a wide string. - // On Windows, UTF-8 is assumed, and on other platforms, - // the current locale is assumed. - static std::wstring ToWide(const std::string& str); - static std::wstring ToWide(const char* str); - - // Convert a wide string to a narrow string. - // On Windows, UTF-8 is assumed, and on other platforms, - // the current locale is assumed. - static std::string ToNarrow(const std::wstring& str); - static std::string ToNarrow(const wchar_t* str); - -#if defined(_WIN32) - /** - * Convert the path to an extended length path to avoid MAX_PATH length - * limitations on Windows. If the input is a local path the result will be - * prefixed with \\?\; if the input is instead a network path, the result - * will be prefixed with \\?\UNC\. All output will also be converted to - * absolute paths with Windows-style backslashes. - **/ - static std::wstring ToWindowsExtendedPath(std::string const&); -#endif - -#endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING - -}; // class Encoding -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/EncodingC.c b/thirdparty/KWSys/adios2sys/EncodingC.c deleted file mode 100644 index c1315b2d53..0000000000 --- a/thirdparty/KWSys/adios2sys/EncodingC.c +++ /dev/null @@ -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 - -#ifdef _WIN32 -#include -#endif - -size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* str, size_t n) -{ - if (str == 0) { - return (size_t)-1; - } -#ifdef _WIN32 - return MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest, - (int)n) - - 1; -#else - return mbstowcs(dest, str, n); -#endif -} - -wchar_t* kwsysEncoding_DupToWide(const char* str) -{ - wchar_t* ret = NULL; - size_t length = kwsysEncoding_mbstowcs(NULL, str, 0) + 1; - if (length > 0) { - ret = (wchar_t*)malloc((length) * sizeof(wchar_t)); - if (ret) { - ret[0] = 0; - kwsysEncoding_mbstowcs(ret, str, length); - } - } - return ret; -} - -size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* str, size_t n) -{ - if (str == 0) { - return (size_t)-1; - } -#ifdef _WIN32 - return WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest, - (int)n, NULL, NULL) - - 1; -#else - return wcstombs(dest, str, n); -#endif -} - -char* kwsysEncoding_DupToNarrow(const wchar_t* str) -{ - char* ret = NULL; - size_t length = kwsysEncoding_wcstombs(0, str, 0) + 1; - if (length > 0) { - ret = (char*)malloc(length); - if (ret) { - ret[0] = 0; - kwsysEncoding_wcstombs(ret, str, length); - } - } - return ret; -} diff --git a/thirdparty/KWSys/adios2sys/EncodingCXX.cxx b/thirdparty/KWSys/adios2sys/EncodingCXX.cxx deleted file mode 100644 index a1fe040d25..0000000000 --- a/thirdparty/KWSys/adios2sys/EncodingCXX.cxx +++ /dev/null @@ -1,277 +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 -#include -#include - -#ifdef _MSC_VER -#pragma warning(disable : 4786) -#endif - -// Windows API. -#if defined(_WIN32) -#include - -#include -#include -#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 av1(ac); - std::vector 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] = KWSYS_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] = KWSYS_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]) : KWSYS_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]) : KWSYS_NULLPTR; - } - } - - return *this; -} - -int Encoding::CommandLineArguments::argc() const -{ - return static_cast(this->argv_.size() - 1); -} - -char const* const* Encoding::CommandLineArguments::argv() const -{ - return &this->argv_[0]; -} - -#if KWSYS_STL_HAS_WSTRING - -std::wstring Encoding::ToWide(const std::string& str) -{ - std::wstring wstr; -#if defined(_WIN32) - const int wlength = MultiByteToWideChar( - KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), int(str.size()), NULL, 0); - if (wlength > 0) { - wchar_t* wdata = new wchar_t[wlength]; - int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), - int(str.size()), wdata, wlength); - if (r > 0) { - wstr = std::wstring(wdata, wlength); - } - delete[] wdata; - } -#else - size_t pos = 0; - size_t nullPos = 0; - do { - if (pos < str.size() && str.at(pos) != '\0') { - wstr += ToWide(str.c_str() + pos); - } - nullPos = str.find('\0', pos); - if (nullPos != 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()), NULL, 0, NULL, NULL); - if (length > 0) { - char* data = new char[length]; - int r = - WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), - int(str.size()), data, length, NULL, NULL); - if (r > 0) { - nstr = std::string(data, length); - } - delete[] data; - } -#else - size_t pos = 0; - size_t nullPos = 0; - do { - if (pos < str.size() && str.at(pos) != '\0') { - nstr += ToNarrow(str.c_str() + pos); - } - nullPos = str.find(wchar_t('\0'), pos); - if (nullPos != 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(KWSYS_NULLPTR, cstr, 0) + 1; - if (length > 0) { - std::vector 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(KWSYS_NULLPTR, wcstr, 0) + 1; - if (length > 0) { - std::vector chars(length); - if (kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0) { - str = &chars[0]; - } - } - return str; -} - -#if defined(_WIN32) -// Convert local paths to UNC style paths -std::wstring Encoding::ToWindowsExtendedPath(std::string const& source) -{ - std::wstring wsource = Encoding::ToWide(source); - - // Resolve any relative paths - DWORD wfull_len; - - /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that - * won't return a large enough buffer size if the input is too small */ - wfull_len = GetFullPathNameW(wsource.c_str(), 0, NULL, NULL) + 3; - std::vector wfull(wfull_len); - GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], NULL); - - /* This should get the correct size without any extra padding from the - * previous size workaround. */ - wfull_len = static_cast(wcslen(&wfull[0])); - - if (wfull_len >= 2 && isalpha(wfull[0]) && - wfull[1] == L':') { /* C:\Foo\bar\FooBar.txt */ - return L"\\\\?\\" + std::wstring(&wfull[0]); - } else if (wfull_len >= 2 && wfull[0] == L'\\' && - wfull[1] == L'\\') { /* Starts with \\ */ - if (wfull_len >= 4 && wfull[2] == L'?' && - wfull[3] == L'\\') { /* Starts with \\?\ */ - if (wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' && - wfull[6] == L'C' && - wfull[7] == L'\\') { /* \\?\UNC\Foo\bar\FooBar.txt */ - return std::wstring(&wfull[0]); - } else if (wfull_len >= 6 && isalpha(wfull[4]) && - wfull[5] == L':') { /* \\?\C:\Foo\bar\FooBar.txt */ - return std::wstring(&wfull[0]); - } else if (wfull_len >= 5) { /* \\?\Foo\bar\FooBar.txt */ - return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]); - } - } else if (wfull_len >= 4 && wfull[2] == L'.' && - wfull[3] == L'\\') { /* Starts with \\.\ a device name */ - if (wfull_len >= 6 && isalpha(wfull[4]) && - wfull[5] == L':') { /* \\.\C:\Foo\bar\FooBar.txt */ - return L"\\\\?\\" + std::wstring(&wfull[4]); - } else if (wfull_len >= - 5) { /* \\.\Foo\bar\ Device name is left unchanged */ - return std::wstring(&wfull[0]); - } - } else if (wfull_len >= 3) { /* \\Foo\bar\FooBar.txt */ - return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]); - } - } - - // If this case has been reached, then the path is invalid. Leave it - // unchanged - return Encoding::ToWide(source); -} -#endif - -#endif // KWSYS_STL_HAS_WSTRING - -} // namespace KWSYS_NAMESPACE diff --git a/thirdparty/KWSys/adios2sys/ExtraTest.cmake.in b/thirdparty/KWSys/adios2sys/ExtraTest.cmake.in deleted file mode 100644 index e8c0a1cdb1..0000000000 --- a/thirdparty/KWSys/adios2sys/ExtraTest.cmake.in +++ /dev/null @@ -1 +0,0 @@ -MESSAGE("*** This message is generated by message inside a file that is included in DartTestfile.txt ***") diff --git a/thirdparty/KWSys/adios2sys/FStream.cxx b/thirdparty/KWSys/adios2sys/FStream.cxx deleted file mode 100644 index 3c44a6fa01..0000000000 --- a/thirdparty/KWSys/adios2sys/FStream.cxx +++ /dev/null @@ -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(bom), 2); - if (!in.good()) { - in.clear(); - in.seekg(orig); - return BOM_None; - } - if (bom[0] == 0xEF && bom[1] == 0xBB) { - in.read(reinterpret_cast(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(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(bom + 2), 2); - if (in.good() && bom[2] == 0x00 && bom[3] == 0x00) { - return BOM_UTF32LE; - } - in.seekg(p); - return BOM_UTF16LE; - } - in.clear(); - in.seekg(orig); - return BOM_None; -} - -} // FStream namespace -} // KWSYS_NAMESPACE diff --git a/thirdparty/KWSys/adios2sys/FStream.hxx.in b/thirdparty/KWSys/adios2sys/FStream.hxx.in deleted file mode 100644 index a4c65fe30c..0000000000 --- a/thirdparty/KWSys/adios2sys/FStream.hxx.in +++ /dev/null @@ -1,276 +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 -#if defined(_WIN32) -#if !defined(_MSC_VER) && @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H -#include -#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 -class basic_filebuf : public std::basic_filebuf -{ -#if _MSC_VER >= 1400 -public: - typedef std::basic_filebuf my_base_type; - basic_filebuf* open(char const* s, std::ios_base::openmode mode) - { - const std::wstring wstr = Encoding::ToWindowsExtendedPath(s); - return static_cast(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 > -class basic_efilebuf -{ -public: -#if defined(_MSC_VER) - typedef basic_filebuf internal_buffer_type; -#else - typedef __gnu_cxx::stdio_filebuf 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* ios, - basic_efilebuf* efilebuf) - { -#if !defined(_MSC_VER) - ios->rdbuf(efilebuf->buf_); -#else - static_cast(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 > -class basic_ifstream : public std::basic_istream, - public basic_efilebuf -{ -public: - typedef typename basic_efilebuf::internal_buffer_type - internal_buffer_type; - typedef std::basic_istream internal_stream_type; - - basic_ifstream() - : internal_stream_type(new internal_buffer_type()) - { - this->buf_ = - static_cast(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_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::is_open; - - internal_buffer_type* rdbuf() const { return this->buf_; } - - ~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); } -}; - -template > -class basic_ofstream : public std::basic_ostream, - public basic_efilebuf -{ - using basic_efilebuf::is_open; - -public: - typedef typename basic_efilebuf::internal_buffer_type - internal_buffer_type; - typedef std::basic_ostream internal_stream_type; - - basic_ofstream() - : internal_stream_type(new internal_buffer_type()) - { - this->buf_ = - static_cast(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_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 ifstream; -typedef basic_ofstream ofstream; - -#undef @KWSYS_NAMESPACE@_FStream_NOEXCEPT -#else -using std::ofstream; -using std::ifstream; -#endif - -namespace FStream { -enum BOM -{ - BOM_None, - BOM_UTF8, - BOM_UTF16BE, - BOM_UTF16LE, - BOM_UTF32BE, - BOM_UTF32LE -}; - -// Read a BOM, if one exists. -// If a BOM exists, the stream is advanced to after the BOM. -// This function requires a seekable stream (but not a relative -// seekable stream). -@KWSYS_NAMESPACE@_EXPORT BOM ReadBOM(std::istream& in); -} -} - -#endif diff --git a/thirdparty/KWSys/adios2sys/Glob.cxx b/thirdparty/KWSys/adios2sys/Glob.cxx deleted file mode 100644 index 2b6db78cf8..0000000000 --- a/thirdparty/KWSys/adios2sys/Glob.cxx +++ /dev/null @@ -1,447 +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 -#include -#include - -#include -#include -#include -namespace KWSYS_NAMESPACE { -#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__) -// On Windows and Apple, no difference between lower and upper case -#define KWSYS_GLOB_CASE_INDEPENDENT -#endif - -#if defined(_WIN32) || defined(__CYGWIN__) -// Handle network paths -#define KWSYS_GLOB_SUPPORT_NETWORK_PATHS -#endif - -class GlobInternals -{ -public: - std::vector Files; - std::vector Expressions; -}; - -Glob::Glob() -{ - this->Internals = new GlobInternals; - this->Recurse = false; - this->Relative = ""; - - this->RecurseThroughSymlinks = true; - // RecurseThroughSymlinks is true by default for backwards compatibility, - // not because it's a good idea... - this->FollowedSymlinkCount = 0; - - // Keep separate variables for directory listing for back compatibility - this->ListDirs = true; - this->RecurseListDirs = false; -} - -Glob::~Glob() -{ - delete this->Internals; -} - -std::vector& 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(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::const_iterator pathIt = - std::find(this->VisitedSymlinks.begin(), - this->VisitedSymlinks.end(), canonicalPath); - pathIt != this->VisitedSymlinks.end(); ++pathIt) { - message += *pathIt + "\n"; - } - message += canonicalPath + "/" + fname; - messages->push_back(Message(Glob::cyclicRecursion, message)); - } - } else { - if (this->RecurseListDirs) { - this->AddFile(this->Internals->Files, realname); - } - if (!this->RecurseDirectory(start + 1, realname, messages)) { - return false; - } - } - } else { - if (!this->Internals->Expressions.empty() && - this->Internals->Expressions.rbegin()->find(fname)) { - this->AddFile(this->Internals->Files, realname); - } - } - } - - return true; -} - -void Glob::ProcessDirectory(std::string::size_type start, - const std::string& dir, GlobMessages* messages) -{ - // std::cout << "ProcessDirectory: " << dir << std::endl; - bool last = (start == this->Internals->Expressions.size() - 1); - if (last && this->Recurse) { - this->RecurseDirectory(start, dir, messages); - return; - } - - if (start >= this->Internals->Expressions.size()) { - return; - } - - kwsys::Directory d; - if (!d.Load(dir)) { - return; - } - unsigned long cc; - std::string realname; - std::string fname; - for (cc = 0; cc < d.GetNumberOfFiles(); cc++) { - fname = d.GetFile(cc); - if (fname == "." || fname == "..") { - continue; - } - - if (start == 0) { - realname = dir + fname; - } else { - realname = dir + "/" + fname; - } - -#if defined(KWSYS_GLOB_CASE_INDEPENDENT) - // On case-insensitive file systems convert to lower case for matching. - fname = kwsys::SystemTools::LowerCase(fname); -#endif - - // std::cout << "Look at file: " << fname << std::endl; - // std::cout << "Match: " - // << this->Internals->TextExpressions[start].c_str() << std::endl; - // std::cout << "Real name: " << realname << std::endl; - - if ((!last && !kwsys::SystemTools::FileIsDirectory(realname)) || - (!this->ListDirs && last && - kwsys::SystemTools::FileIsDirectory(realname))) { - continue; - } - - if (this->Internals->Expressions[start].find(fname)) { - if (last) { - this->AddFile(this->Internals->Files, realname); - } else { - this->ProcessDirectory(start + 1, realname, messages); - } - } - } -} - -bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages) -{ - std::string cexpr; - std::string::size_type cc; - std::string expr = inexpr; - - this->Internals->Expressions.clear(); - this->Internals->Files.clear(); - - if (!kwsys::SystemTools::FileIsFullPath(expr)) { - expr = kwsys::SystemTools::GetCurrentWorkingDirectory(); - expr += "/" + inexpr; - } - std::string fexpr = expr; - - std::string::size_type skip = 0; - std::string::size_type last_slash = 0; - for (cc = 0; cc < expr.size(); cc++) { - if (cc > 0 && expr[cc] == '/' && expr[cc - 1] != '\\') { - last_slash = cc; - } - if (cc > 0 && (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') && - expr[cc - 1] != '\\') { - break; - } - } - if (last_slash > 0) { - // std::cout << "I can skip: " << fexpr.substr(0, last_slash) - // << std::endl; - skip = last_slash; - } - if (skip == 0) { -#if defined(KWSYS_GLOB_SUPPORT_NETWORK_PATHS) - // Handle network paths - if (expr[0] == '/' && expr[1] == '/') { - int cnt = 0; - for (cc = 2; cc < expr.size(); cc++) { - if (expr[cc] == '/') { - cnt++; - if (cnt == 2) { - break; - } - } - } - skip = int(cc + 1); - } else -#endif - // Handle drive letters on Windows - if (expr[1] == ':' && expr[0] != '/') { - skip = 2; - } - } - - if (skip > 0) { - expr = expr.substr(skip); - } - - cexpr = ""; - for (cc = 0; cc < expr.size(); cc++) { - int ch = expr[cc]; - if (ch == '/') { - if (!cexpr.empty()) { - this->AddExpression(cexpr); - } - cexpr = ""; - } else { - cexpr.append(1, static_cast(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 KWSYS_NULLPTR; - } - return this->Relative.c_str(); -} - -void Glob::AddFile(std::vector& files, const std::string& file) -{ - if (!this->Relative.empty()) { - files.push_back(kwsys::SystemTools::RelativePath(this->Relative, file)); - } else { - files.push_back(file); - } -} - -} // namespace KWSYS_NAMESPACE diff --git a/thirdparty/KWSys/adios2sys/Glob.hxx.in b/thirdparty/KWSys/adios2sys/Glob.hxx.in deleted file mode 100644 index bd4a176169..0000000000 --- a/thirdparty/KWSys/adios2sys/Glob.hxx.in +++ /dev/null @@ -1,142 +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 -#include - -namespace @KWSYS_NAMESPACE@ { - -class GlobInternals; - -/** \class Glob - * \brief Portable globbing searches. - * - * Globbing expressions are much simpler than regular - * expressions. This class will search for files using - * globbing expressions. - * - * Finds all files that match a given globbing expression. - */ -class @KWSYS_NAMESPACE@_EXPORT Glob -{ -public: - enum MessageType - { - error, - cyclicRecursion - }; - - struct Message - { - MessageType type; - std::string content; - - Message(MessageType t, const std::string& c) - : type(t) - , content(c) - { - } - Message(const Message& msg) - : type(msg.type) - , content(msg.content) - { - } - Message& operator=(Message const& msg) - { - this->type = msg.type; - this->content = msg.content; - return *this; - } - }; - - typedef std::vector GlobMessages; - typedef std::vector::iterator GlobMessagesIterator; - -public: - Glob(); - ~Glob(); - - //! Find all files that match the pattern. - bool FindFiles(const std::string& inexpr, GlobMessages* messages = 0); - - //! Return the list of files that matched. - std::vector& 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& files, const std::string& file); - - GlobInternals* Internals; - bool Recurse; - std::string Relative; - bool RecurseThroughSymlinks; - unsigned int FollowedSymlinkCount; - std::vector VisitedSymlinks; - bool ListDirs; - bool RecurseListDirs; - -private: - Glob(const Glob&); // Not implemented. - void operator=(const Glob&); // Not implemented. -}; - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/IOStream.cxx b/thirdparty/KWSys/adios2sys/IOStream.cxx deleted file mode 100644 index 01ada1f2fc..0000000000 --- a/thirdparty/KWSys/adios2sys/IOStream.cxx +++ /dev/null @@ -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 -#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 // sscanf, sprintf -#include // memchr - -#if defined(_MAX_INT_DIG) -#define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG -#else -#define KWSYS_IOS_INT64_MAX_DIG 32 -#endif - -namespace KWSYS_NAMESPACE { - -// Scan an input stream for an integer value. -static int IOStreamScanStream(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 -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 -std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type) -{ - std::ostream::sentry okay(os); - if (okay) { - try { - // Construct the format string. - char format[8]; - char* f = format; - *f++ = '%'; - if (os.flags() & std::ios_base::showpos) { - *f++ = '+'; - } - if (os.flags() & std::ios_base::showbase) { - *f++ = '#'; - } -#if defined(_MSC_VER) - *f++ = 'I'; - *f++ = '6'; - *f++ = '4'; -#else - *f++ = 'l'; - *f++ = 'l'; -#endif - long bflags = os.flags() & std::ios_base::basefield; - if (bflags == std::ios_base::oct) { - *f++ = 'o'; - } else if (bflags != std::ios_base::hex) { - *f++ = type; - } else if (os.flags() & std::ios_base::uppercase) { - *f++ = 'X'; - } else { - *f++ = 'x'; - } - *f = '\0'; - - // Use sprintf to print to a buffer and then write the - // buffer to the stream. - char buffer[2 * KWSYS_IOS_INT64_MAX_DIG]; - sprintf(buffer, format, value); - os << buffer; - } catch (...) { - os.clear(os.rdstate() | std::ios_base::badbit); - } - } - return os; -} - -#if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG -// Implement input stream operator for IOStreamSLL. -std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value) -{ - return IOStreamScanTemplate(is, value, 'd'); -} - -// Implement input stream operator for IOStreamULL. -std::istream& IOStreamScan(std::istream& is, IOStreamULL& value) -{ - return IOStreamScanTemplate(is, value, 'u'); -} -#endif - -#if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG -// Implement output stream operator for IOStreamSLL. -std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value) -{ - return IOStreamPrintTemplate(os, value, 'd'); -} - -// Implement output stream operator for IOStreamULL. -std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value) -{ - return IOStreamPrintTemplate(os, value, 'u'); -} -#endif - -} // namespace KWSYS_NAMESPACE - -#else - -namespace KWSYS_NAMESPACE { - -// Create one public symbol in this object file to avoid warnings from -// archivers. -void IOStreamSymbolToAvoidWarning(); -void IOStreamSymbolToAvoidWarning() -{ -} - -} // namespace KWSYS_NAMESPACE - -#endif // KWSYS_IOS_NEED_OPERATORS_LL diff --git a/thirdparty/KWSys/adios2sys/IOStream.hxx.in b/thirdparty/KWSys/adios2sys/IOStream.hxx.in deleted file mode 100644 index de3a2e6344..0000000000 --- a/thirdparty/KWSys/adios2sys/IOStream.hxx.in +++ /dev/null @@ -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 - -/* Define these macros temporarily to keep the code readable. */ -#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif - -/* Whether istream supports long long. */ -#define @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG \ - @KWSYS_IOS_HAS_ISTREAM_LONG_LONG@ - -/* Whether ostream supports long long. */ -#define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG \ - @KWSYS_IOS_HAS_OSTREAM_LONG_LONG@ - -/* Determine whether we need to define the streaming operators for - long long or __int64. */ -#if @KWSYS_USE_LONG_LONG@ -#if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG || \ - !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG -#define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 -namespace @KWSYS_NAMESPACE@ { -typedef long long IOStreamSLL; -typedef unsigned long long IOStreamULL; -} -#endif -#elif defined(_MSC_VER) && _MSC_VER < 1300 -#define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 -namespace @KWSYS_NAMESPACE@ { -typedef __int64 IOStreamSLL; -typedef unsigned __int64 IOStreamULL; -} -#endif -#if !defined(@KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL) -#define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 0 -#endif - -#if @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL -#if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG - -/* Input stream operator implementation functions. */ -namespace @KWSYS_NAMESPACE@ { -kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamSLL&); -kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamULL&); -} - -/* Provide input stream operator for long long. */ -#if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_LONG_LONG) && \ - !defined(KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED) -#define KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED -#define @KWSYS_NAMESPACE@_IOS_ISTREAM_LONG_LONG_DEFINED -inline std::istream& operator>>(std::istream& is, - @KWSYS_NAMESPACE@::IOStreamSLL& value) -{ - return @KWSYS_NAMESPACE@::IOStreamScan(is, value); -} -#endif - -/* Provide input stream operator for unsigned long long. */ -#if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_UNSIGNED_LONG_LONG) && \ - !defined(KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED) -#define KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED -#define @KWSYS_NAMESPACE@_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED -inline std::istream& operator>>(std::istream& is, - @KWSYS_NAMESPACE@::IOStreamULL& value) -{ - return @KWSYS_NAMESPACE@::IOStreamScan(is, value); -} -#endif -#endif /* !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG */ - -#if !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG - -/* Output stream operator implementation functions. */ -namespace @KWSYS_NAMESPACE@ { -kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamSLL); -kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamULL); -} - -/* Provide output stream operator for long long. */ -#if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_LONG_LONG) && \ - !defined(KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED) -#define KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED -#define @KWSYS_NAMESPACE@_IOS_OSTREAM_LONG_LONG_DEFINED -inline std::ostream& operator<<(std::ostream& os, - @KWSYS_NAMESPACE@::IOStreamSLL value) -{ - return @KWSYS_NAMESPACE@::IOStreamPrint(os, value); -} -#endif - -/* Provide output stream operator for unsigned long long. */ -#if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_UNSIGNED_LONG_LONG) && \ - !defined(KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED) -#define KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED -#define @KWSYS_NAMESPACE@_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED -inline std::ostream& operator<<(std::ostream& os, - @KWSYS_NAMESPACE@::IOStreamULL value) -{ - return @KWSYS_NAMESPACE@::IOStreamPrint(os, value); -} -#endif -#endif /* !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG */ -#endif /* @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL */ - -/* Undefine temporary macros. */ -#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#undef kwsysEXPORT -#endif - -/* If building a C++ file in kwsys itself, give the source file - access to the macros without a configured namespace. */ -#if defined(KWSYS_NAMESPACE) -#define KWSYS_IOS_HAS_ISTREAM_LONG_LONG \ - @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG -#define KWSYS_IOS_HAS_OSTREAM_LONG_LONG \ - @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG -#define KWSYS_IOS_NEED_OPERATORS_LL @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/MD5.c b/thirdparty/KWSys/adios2sys/MD5.c deleted file mode 100644 index 3188fb67ac..0000000000 --- a/thirdparty/KWSys/adios2sys/MD5.c +++ /dev/null @@ -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 /* size_t */ -#include /* malloc, free */ -#include /* memcpy, strlen */ - -/* This MD5 implementation has been taken from a third party. Slight - modifications to the arrangement of the code have been made to put - it in a single source file instead of a separate header and - implementation file. */ - -#if defined(__clang__) && !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 - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s -{ - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -#define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - -static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) -{ - md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], - d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t* X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t*)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t*)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t*)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t* xp = data; - int i; - -#if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -#else -#define xbuf X /* (static only) */ -#endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = - (md5_word_t)(xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24)); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - -/* Round 1. */ -/* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + F(b, c, d) + X[k] + (Ti); \ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - -/* Round 2. */ -/* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + G(b, c, d) + X[k] + (Ti); \ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - -/* Round 3. */ -/* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + H(b, c, d) + X[k] + (Ti); \ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - -/* Round 4. */ -/* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + I(b, c, d) + X[k] + (Ti); \ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -/* Initialize the algorithm. */ -static void md5_init(md5_state_t* pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -/* Append a string to the message. */ -static void md5_append(md5_state_t* pms, const md5_byte_t* data, size_t nbytes) -{ - const md5_byte_t* p = data; - size_t left = nbytes; - size_t offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += (md5_word_t)(nbytes >> 29); - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -/* Finish the message and return the digest. */ -static void md5_finish(md5_state_t* pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} - -#if defined(__clang__) && !defined(__INTEL_COMPILER) -#pragma clang diagnostic pop -#endif - -/* Wrap up the MD5 state in our opaque structure. */ -struct kwsysMD5_s -{ - md5_state_t md5_state; -}; - -kwsysMD5* kwsysMD5_New(void) -{ - /* Allocate a process control structure. */ - kwsysMD5* md5 = (kwsysMD5*)malloc(sizeof(kwsysMD5)); - if (!md5) { - return 0; - } - return md5; -} - -void kwsysMD5_Delete(kwsysMD5* md5) -{ - /* Make sure we have an instance. */ - if (!md5) { - return; - } - - /* Free memory. */ - free(md5); -} - -void kwsysMD5_Initialize(kwsysMD5* md5) -{ - md5_init(&md5->md5_state); -} - -void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, int length) -{ - size_t dlen; - if (length < 0) { - dlen = strlen((char const*)data); - } else { - dlen = (size_t)length; - } - md5_append(&md5->md5_state, (md5_byte_t const*)data, dlen); -} - -void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]) -{ - md5_finish(&md5->md5_state, (md5_byte_t*)digest); -} - -void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]) -{ - unsigned char digest[16]; - kwsysMD5_Finalize(md5, digest); - kwsysMD5_DigestToHex(digest, buffer); -} - -void kwsysMD5_DigestToHex(unsigned char const digest[16], char buffer[32]) -{ - /* Map from 4-bit index to hexadecimal representation. */ - static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - - /* Map each 4-bit block separately. */ - char* out = buffer; - int i; - for (i = 0; i < 16; ++i) { - *out++ = hex[digest[i] >> 4]; - *out++ = hex[digest[i] & 0xF]; - } -} diff --git a/thirdparty/KWSys/adios2sys/MD5.h.in b/thirdparty/KWSys/adios2sys/MD5.h.in deleted file mode 100644 index c257f7f9ae..0000000000 --- a/thirdparty/KWSys/adios2sys/MD5.h.in +++ /dev/null @@ -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 diff --git a/thirdparty/KWSys/adios2sys/Process.h.in b/thirdparty/KWSys/adios2sys/Process.h.in deleted file mode 100644 index daf334a616..0000000000 --- a/thirdparty/KWSys/adios2sys/Process.h.in +++ /dev/null @@ -1,540 +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 diff --git a/thirdparty/KWSys/adios2sys/ProcessUNIX.c b/thirdparty/KWSys/adios2sys/ProcessUNIX.c deleted file mode 100644 index 1e80b39cba..0000000000 --- a/thirdparty/KWSys/adios2sys/ProcessUNIX.c +++ /dev/null @@ -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 */ -#include /* isspace */ -#include /* DIR, dirent */ -#include /* errno */ -#include /* fcntl */ -#include /* sigaction */ -#include /* ptrdiff_t */ -#include /* snprintf */ -#include /* malloc, free */ -#include /* strdup, strerror, memset */ -#include /* open mode */ -#include /* struct timeval */ -#include /* pid_t, fd_set */ -#include /* waitpid */ -#include /* gettimeofday */ -#include /* 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 -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 termianted. */ - cp->ForkPIDs[i] = 0; - if (--cp->CommandsLeft == 0) { - /* All children have terminated. Close the signal pipe - write end so that no more notifications are sent to this - object. */ - kwsysProcessCleanupDescriptor(&cp->SignalPipe); - - /* TODO: Once the children have terminated, switch - WaitForData to use a non-blocking read to get the - rest of the data from the pipe. This is needed when - grandchildren keep the output pipes open. */ - } - } else if (result < 0 && cp->State != kwsysProcess_State_Error) { - /* Unexpected error. Report the first time this happens. */ - strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); - cp->State = kwsysProcess_State_Error; - } - } - } - - /* Re-enable signals. */ - sigprocmask(SIG_SETMASK, &old_mask, 0); -} - -static int kwsysProcessSetupOutputPipeFile(int* p, const char* name) -{ - int fout; - if (!name) { - return 1; - } - - /* Close the existing descriptor. */ - kwsysProcessCleanupDescriptor(p); - - /* Open a file for the pipe to write. */ - if ((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { - return 0; - } - - /* Set close-on-exec flag on the pipe's end. */ - if (fcntl(fout, F_SETFD, FD_CLOEXEC) < 0) { - 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(); -} diff --git a/thirdparty/KWSys/adios2sys/ProcessWin32.c b/thirdparty/KWSys/adios2sys/ProcessWin32.c deleted file mode 100644 index 82fdc74786..0000000000 --- a/thirdparty/KWSys/adios2sys/ProcessWin32.c +++ /dev/null @@ -1,2772 +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 API */ -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#define KWSYS_WINDOWS_DEPRECATED_GetVersionEx -#endif -#include /* _unlink */ -#include /* sprintf */ -#include /* strlen, strdup */ -#ifdef __WATCOMC__ -#define _unlink unlink -#endif - -#ifndef _MAX_FNAME -#define _MAX_FNAME 4096 -#endif -#ifndef _MAX_PATH -#define _MAX_PATH 4096 -#endif - -#ifdef _MSC_VER -#pragma warning(pop) -#pragma warning(disable : 4514) -#pragma warning(disable : 4706) -#endif - -#if defined(__BORLANDC__) -#pragma warn - 8004 /* assigned a value that is never used */ -#pragma warn - 8060 /* Assignment inside if() condition. */ -#endif - -/* There are pipes for the process pipeline's stdout and stderr. */ -#define KWSYSPE_PIPE_COUNT 2 -#define KWSYSPE_PIPE_STDOUT 0 -#define KWSYSPE_PIPE_STDERR 1 - -/* The maximum amount to read from a pipe at a time. */ -#define KWSYSPE_PIPE_BUFFER_SIZE 1024 - -/* Debug output macro. */ -#if 0 -#define KWSYSPE_DEBUG(x) \ - ((void*)cp == (void*)0x00226DE0 \ - ? (fprintf(stderr, "%d/%p/%d ", (int)GetCurrentProcessId(), cp, \ - __LINE__), \ - fprintf x, fflush(stderr), 1) \ - : (1)) -#else -#define KWSYSPE_DEBUG(x) (void)1 -#endif - -typedef LARGE_INTEGER kwsysProcessTime; - -typedef struct kwsysProcessCreateInformation_s -{ - /* Windows child startup control data. */ - STARTUPINFOW StartupInfo; - - /* Original handles before making inherited duplicates. */ - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; -} kwsysProcessCreateInformation; - -typedef struct kwsysProcessPipeData_s kwsysProcessPipeData; -static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd); -static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, - kwsysProcessPipeData* td); -static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd); -static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, - kwsysProcessPipeData* td); -static int kwsysProcessInitialize(kwsysProcess* cp); -static DWORD kwsysProcessCreate(kwsysProcess* cp, int index, - kwsysProcessCreateInformation* si); -static void kwsysProcessDestroy(kwsysProcess* cp, int event); -static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name); -static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle); -static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle); -static void kwsysProcessCleanupHandle(PHANDLE h); -static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error); -static void kwsysProcessCleanErrorMessage(kwsysProcess* cp); -static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, - kwsysProcessTime* timeoutTime); -static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, - double* userTimeout, - kwsysProcessTime* timeoutLength); -static kwsysProcessTime kwsysProcessTimeGetCurrent(void); -static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t); -static double kwsysProcessTimeToDouble(kwsysProcessTime t); -static kwsysProcessTime kwsysProcessTimeFromDouble(double d); -static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); -static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, - kwsysProcessTime in2); -static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, - kwsysProcessTime in2); -static void kwsysProcessSetExitException(kwsysProcess* cp, int code); -static void 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) -#else -#pragma warning(disable : 4996) -#endif -#endif - GetVersionEx(&osv); -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -#pragma warning(pop) -#endif - if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - /* Win9x no longer supported. */ - kwsysProcess_Delete(cp); - return 0; - } - - /* Initially no thread owns the mutex. Initialize semaphore to 1. */ - if (!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* Initially no data are available. Initialize semaphore to 0. */ - if (!(cp->Full = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* Create the thread to read each pipe. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - DWORD dummy = 0; - - /* Assign the thread its index. */ - cp->Pipe[i].Index = i; - - /* Give the thread a pointer back to the kwsysProcess instance. */ - cp->Pipe[i].Process = cp; - - /* No process is yet running. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* The pipe is not yet reset. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* The thread's buffer is initially empty. Initialize semaphore to 1. */ - if (!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* Create the reading thread. It will block immediately. The - thread will not make deeply nested calls, so we need only a - small stack. */ - if (!(cp->Pipe[i].Reader.Thread = CreateThread( - 0, 1024, kwsysProcessPipeThreadRead, &cp->Pipe[i], 0, &dummy))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* No process is yet running. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* The pipe is not yet reset. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* The waker should not wake immediately. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* Create the waking thread. It will block immediately. The - thread will not make deeply nested calls, so we need only a - small stack. */ - if (!(cp->Pipe[i].Waker.Thread = CreateThread( - 0, 1024, kwsysProcessPipeThreadWake, &cp->Pipe[i], 0, &dummy))) { - kwsysProcess_Delete(cp); - return 0; - } - } - for (i = 0; i < 3; ++i) { - cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; - } - - return cp; -} - -void kwsysProcess_Delete(kwsysProcess* cp) -{ - int i; - - /* Make sure we have an instance. */ - if (!cp) { - return; - } - - /* If the process is executing, wait for it to finish. */ - if (cp->State == kwsysProcess_State_Executing) { - if (cp->Detached) { - kwsysProcess_Disown(cp); - } else { - kwsysProcess_WaitForExit(cp, 0); - } - } - - /* We are deleting the kwsysProcess instance. */ - cp->Deleting = 1; - - /* Terminate each of the threads. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - /* Terminate this reading thread. */ - if (cp->Pipe[i].Reader.Thread) { - /* Signal the thread we are ready for it. It will terminate - immediately since Deleting is set. */ - ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0); - - /* Wait for the thread to exit. */ - WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE); - - /* Close the handle to the thread. */ - kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread); - } - - /* Terminate this waking thread. */ - if (cp->Pipe[i].Waker.Thread) { - /* Signal the thread we are ready for it. It will terminate - immediately since Deleting is set. */ - ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0); - - /* Wait for the thread to exit. */ - WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE); - - /* Close the handle to the thread. */ - kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread); - } - - /* Cleanup the pipe's semaphores. */ - kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Ready); - kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Go); - kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Reset); - kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Ready); - kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Go); - kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Reset); - } - - /* Close the shared semaphores. */ - kwsysProcessCleanupHandle(&cp->SharedIndexMutex); - kwsysProcessCleanupHandle(&cp->Full); - - /* Free memory. */ - kwsysProcess_SetCommand(cp, 0); - kwsysProcess_SetWorkingDirectory(cp, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); - 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 | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); - error = GetLastError(); /* Check now in case free changes this. */ - free(wstdin); - if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) { - kwsysProcessCleanup(cp, error); - return; - } - } else if (cp->PipeSharedSTDIN) { - /* Share this process's stdin with the child. */ - kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]); - } else if (cp->PipeNativeSTDIN[0]) { - /* Use the provided native pipe. */ - kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]); - } else { - /* Explicitly give the child no stdin. */ - cp->PipeChildStd[0] = INVALID_HANDLE_VALUE; - } - - /* Create the output pipe for the last process. - We always create this so the pipe thread can run even if we - do not end up giving the write end to the child below. */ - if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read, - &cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - - if (cp->PipeFileSTDOUT) { - /* Use a file for stdout. */ - DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1], - cp->PipeFileSTDOUT); - if (error) { - kwsysProcessCleanup(cp, error); - return; - } - } else if (cp->PipeSharedSTDOUT) { - /* Use the parent stdout. */ - kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]); - } else if (cp->PipeNativeSTDOUT[1]) { - /* Use the given handle for stdout. */ - kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]); - } else { - /* Use our pipe for stdout. Duplicate the handle since our waker - thread will use the original. Do not make it inherited yet. */ - if (!DuplicateHandle(GetCurrentProcess(), - cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, - GetCurrentProcess(), &cp->PipeChildStd[1], 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - } - - /* Create stderr pipe to be shared by all processes in the pipeline. - We always create this so the pipe thread can run even if we do not - end up giving the write end to the child below. */ - if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read, - &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - - if (cp->PipeFileSTDERR) { - /* Use a file for stderr. */ - DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2], - cp->PipeFileSTDERR); - if (error) { - kwsysProcessCleanup(cp, error); - return; - } - } else if (cp->PipeSharedSTDERR) { - /* Use the parent stderr. */ - kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]); - } else if (cp->PipeNativeSTDERR[1]) { - /* Use the given handle for stderr. */ - kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]); - } else { - /* Use our pipe for stderr. Duplicate the handle since our waker - thread will use the original. Do not make it inherited yet. */ - if (!DuplicateHandle(GetCurrentProcess(), - cp->Pipe[KWSYSPE_PIPE_STDERR].Write, - GetCurrentProcess(), &cp->PipeChildStd[2], 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - } - - /* Create the pipeline of processes. */ - { - /* Child startup control data. */ - kwsysProcessCreateInformation si; - HANDLE nextStdInput = cp->PipeChildStd[0]; - - /* Initialize startup info data. */ - ZeroMemory(&si, sizeof(si)); - si.StartupInfo.cb = sizeof(si.StartupInfo); - - /* Decide whether a child window should be shown. */ - si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; - si.StartupInfo.wShowWindow = - (unsigned short)(cp->HideWindow ? SW_HIDE : SW_SHOWDEFAULT); - - /* Connect the child's output pipes to the threads. */ - si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; - - for (i = 0; i < cp->NumberOfCommands; ++i) { - /* Setup the process's pipes. */ - si.hStdInput = nextStdInput; - if (i == cp->NumberOfCommands - 1) { - /* The last child gets the overall stdout. */ - nextStdInput = INVALID_HANDLE_VALUE; - si.hStdOutput = cp->PipeChildStd[1]; - } else { - /* Create a pipe to sit between the children. */ - HANDLE p[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; - if (!CreatePipe(&p[0], &p[1], 0, 0)) { - DWORD error = GetLastError(); - if (nextStdInput != cp->PipeChildStd[0]) { - kwsysProcessCleanupHandle(&nextStdInput); - } - kwsysProcessCleanup(cp, error); - return; - } - nextStdInput = p[0]; - si.hStdOutput = p[1]; - } - si.hStdError = - cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2]; - - { - DWORD error = kwsysProcessCreate(cp, i, &si); - - /* Close our copies of pipes used between children. */ - if (si.hStdInput != cp->PipeChildStd[0]) { - kwsysProcessCleanupHandle(&si.hStdInput); - } - if (si.hStdOutput != cp->PipeChildStd[1]) { - kwsysProcessCleanupHandle(&si.hStdOutput); - } - if (si.hStdError != cp->PipeChildStd[2] && !cp->MergeOutput) { - kwsysProcessCleanupHandle(&si.hStdError); - } - if (!error) { - cp->ProcessEvents[i + 1] = cp->ProcessInformation[i].hProcess; - } else { - if (nextStdInput != cp->PipeChildStd[0]) { - kwsysProcessCleanupHandle(&nextStdInput); - } - kwsysProcessCleanup(cp, error); - return; - } - } - } - } - - /* The parent process does not need the child's pipe ends. */ - for (i = 0; i < 3; ++i) { - kwsysProcessCleanupHandle(&cp->PipeChildStd[i]); - } - - /* Restore the working directory. */ - if (cp->RealWorkingDirectory) { - SetCurrentDirectoryW(cp->RealWorkingDirectory); - free(cp->RealWorkingDirectory); - cp->RealWorkingDirectory = 0; - } - - /* The timeout period starts now. */ - cp->StartTime = kwsysProcessTimeGetCurrent(); - cp->TimeoutTime = kwsysProcessTimeFromDouble(-1); - - /* All processes in the pipeline have been started in suspended - mode. Resume them all now. */ - for (i = 0; i < cp->NumberOfCommands; ++i) { - ResumeThread(cp->ProcessInformation[i].hThread); - } - - /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */ - /* Tell the pipe threads that a process has started. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0); - ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0); - } - - /* We don't care about the children's main threads. */ - for (i = 0; i < cp->NumberOfCommands; ++i) { - kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); - } - - /* No pipe has reported data. */ - cp->CurrentIndex = KWSYSPE_PIPE_COUNT; - cp->PipesLeft = KWSYSPE_PIPE_COUNT; - - /* The process has now started. */ - cp->State = kwsysProcess_State_Executing; - cp->Detached = cp->OptionDetach; -} - -void kwsysProcess_Disown(kwsysProcess* cp) -{ - int i; - - /* Make sure we are executing a detached process. */ - if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing || - cp->TimeoutExpired || cp->Killed || cp->Terminated) { - return; - } - - /* Disable the reading threads. */ - kwsysProcessDisablePipeThreads(cp); - - /* Wait for all pipe threads to reset. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE); - WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE); - } - - /* We will not wait for exit, so cleanup now. */ - kwsysProcessCleanup(cp, 0); - - /* The process has been disowned. */ - cp->State = kwsysProcess_State_Disowned; -} - -int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length, - double* userTimeout) -{ - kwsysProcessTime userStartTime; - kwsysProcessTime timeoutLength; - kwsysProcessTime timeoutTime; - DWORD timeout; - int user; - int done = 0; - int expired = 0; - int pipeId = kwsysProcess_Pipe_None; - DWORD w; - - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed || - cp->TimeoutExpired) { - return kwsysProcess_Pipe_None; - } - - /* Record the time at which user timeout period starts. */ - userStartTime = kwsysProcessTimeGetCurrent(); - - /* Calculate the time at which a timeout will expire, and whether it - is the user or process timeout. */ - user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime); - - /* Loop until we have a reason to return. */ - while (!done && cp->PipesLeft > 0) { - /* If we previously got data from a thread, let it know we are - done with the data. */ - if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { - KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); - cp->CurrentIndex = KWSYSPE_PIPE_COUNT; - } - - /* Setup a timeout if required. */ - if (kwsysProcessGetTimeoutLeft(&timeoutTime, user ? userTimeout : 0, - &timeoutLength)) { - /* Timeout has already expired. */ - expired = 1; - break; - } - if (timeoutTime.QuadPart < 0) { - timeout = INFINITE; - } else { - timeout = kwsysProcessTimeToDWORD(timeoutLength); - } - - /* Wait for a pipe's thread to signal or a process to terminate. */ - w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents, 0, - timeout); - if (w == WAIT_TIMEOUT) { - /* Timeout has expired. */ - expired = 1; - done = 1; - } else if (w == WAIT_OBJECT_0) { - /* Save the index of the reporting thread and release the mutex. - The thread will block until we signal its Empty mutex. */ - cp->CurrentIndex = cp->SharedIndex; - ReleaseSemaphore(cp->SharedIndexMutex, 1, 0); - - /* Data are available or a pipe closed. */ - if (cp->Pipe[cp->CurrentIndex].Closed) { - /* The pipe closed at the write end. Close the read end and - inform the wakeup thread it is done with this process. */ - kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read); - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Waker.Go, 1, 0); - KWSYSPE_DEBUG((stderr, "wakeup %d\n", cp->CurrentIndex)); - --cp->PipesLeft; - } else if (data && length) { - /* Report this data. */ - *data = cp->Pipe[cp->CurrentIndex].DataBuffer; - *length = cp->Pipe[cp->CurrentIndex].DataLength; - switch (cp->CurrentIndex) { - case KWSYSPE_PIPE_STDOUT: - pipeId = kwsysProcess_Pipe_STDOUT; - break; - case KWSYSPE_PIPE_STDERR: - pipeId = kwsysProcess_Pipe_STDERR; - break; - } - done = 1; - } - } else { - /* A process has terminated. */ - kwsysProcessDestroy(cp, w - WAIT_OBJECT_0); - } - } - - /* Update the user timeout. */ - if (userTimeout) { - kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent(); - kwsysProcessTime difference = - kwsysProcessTimeSubtract(userEndTime, userStartTime); - double d = kwsysProcessTimeToDouble(difference); - *userTimeout -= d; - if (*userTimeout < 0) { - *userTimeout = 0; - } - } - - /* Check what happened. */ - if (pipeId) { - /* Data are ready on a pipe. */ - return pipeId; - } else if (expired) { - /* A timeout has expired. */ - if (user) { - /* The user timeout has expired. It has no time left. */ - return kwsysProcess_Pipe_Timeout; - } else { - /* The process timeout has expired. Kill the child now. */ - KWSYSPE_DEBUG((stderr, "killing child because timeout expired\n")); - kwsysProcess_Kill(cp); - cp->TimeoutExpired = 1; - cp->Killed = 0; - return kwsysProcess_Pipe_None; - } - } else { - /* The children have terminated and no more data are available. */ - return kwsysProcess_Pipe_None; - } -} - -int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) -{ - int i; - int pipe; - - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing) { - return 1; - } - - /* Wait for the process to terminate. Ignore all data. */ - while ((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) { - if (pipe == kwsysProcess_Pipe_Timeout) { - /* The user timeout has expired. */ - return 0; - } - } - - KWSYSPE_DEBUG((stderr, "no more data\n")); - - /* When the last pipe closes in WaitForData, the loop terminates - without releasing the pipe's thread. Release it now. */ - if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { - KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); - cp->CurrentIndex = KWSYSPE_PIPE_COUNT; - } - - /* Wait for all pipe threads to reset. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - KWSYSPE_DEBUG((stderr, "waiting reader reset %d\n", i)); - WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE); - KWSYSPE_DEBUG((stderr, "waiting waker reset %d\n", i)); - WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE); - } - - /* ---- It is now safe again to call kwsysProcessCleanup. ----- */ - /* Close all the pipes. */ - kwsysProcessCleanup(cp, 0); - - /* Determine the outcome. */ - if (cp->Killed) { - /* We killed the child. */ - cp->State = kwsysProcess_State_Killed; - } else if (cp->TimeoutExpired) { - /* The timeout expired. */ - cp->State = kwsysProcess_State_Expired; - } else { - /* The children exited. Report the outcome of the 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) -#else -#pragma warning(disable : 4996) -#endif -#endif - GetVersionEx(&osv); -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -#pragma warning(pop) -#endif - self->NT4 = - (osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1 - : 0; - - /* Initialize the selected implementation. */ - if (!(self->NT4 ? kwsysProcess_List__New_NT4(self) - : kwsysProcess_List__New_Snapshot(self))) { - kwsysProcess_List_Delete(self); - return 0; - } - - /* Update to the current set of processes. */ - if (!kwsysProcess_List_Update(self)) { - kwsysProcess_List_Delete(self); - return 0; - } - return self; -} - -static void kwsysProcess_List_Delete(kwsysProcess_List* self) -{ - if (self) { - if (self->NT4) { - kwsysProcess_List__Delete_NT4(self); - } else { - kwsysProcess_List__Delete_Snapshot(self); - } - free(self); - } -} - -static int kwsysProcess_List_Update(kwsysProcess_List* self) -{ - return self ? (self->NT4 ? kwsysProcess_List__Update_NT4(self) - : kwsysProcess_List__Update_Snapshot(self)) - : 0; -} - -static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self) -{ - return self ? (self->NT4 ? kwsysProcess_List__GetProcessId_NT4(self) - : kwsysProcess_List__GetProcessId_Snapshot(self)) - : -1; -} - -static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self) -{ - return self ? (self->NT4 ? kwsysProcess_List__GetParentId_NT4(self) - : kwsysProcess_List__GetParentId_Snapshot(self)) - : -1; -} - -static int kwsysProcess_List_NextProcess(kwsysProcess_List* self) -{ - return (self ? (self->NT4 ? kwsysProcess_List__Next_NT4(self) - : kwsysProcess_List__Next_Snapshot(self)) - : 0); -} - -static int kwsysProcess_List__New_NT4(kwsysProcess_List* self) -{ - /* Get a handle to the NT runtime module that should already be - loaded in this program. This does not actually increment the - reference count to the module so we do not need to close the - handle. */ - HMODULE hNT = GetModuleHandleW(L"ntdll.dll"); - if (hNT) { - /* Get pointers to the needed API functions. */ - self->P_ZwQuerySystemInformation = - ((ZwQuerySystemInformationType)GetProcAddress( - hNT, "ZwQuerySystemInformation")); - } - if (!self->P_ZwQuerySystemInformation) { - return 0; - } - - /* Allocate an initial process information buffer. */ - self->BufferSize = 32768; - self->Buffer = (char*)malloc(self->BufferSize); - return self->Buffer ? 1 : 0; -} - -static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self) -{ - /* Free the process information buffer. */ - free(self->Buffer); -} - -static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self) -{ - self->CurrentInfo = 0; - for (;;) { - /* Query number 5 is for system process list. */ - NTSTATUS status = - self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0); - if (status == STATUS_INFO_LENGTH_MISMATCH) { - /* The query requires a bigger buffer. */ - int newBufferSize = self->BufferSize * 2; - char* newBuffer = (char*)malloc(newBufferSize); - if (newBuffer) { - free(self->Buffer); - self->Buffer = newBuffer; - self->BufferSize = newBufferSize; - } else { - return 0; - } - } else if (status >= 0) { - /* The query succeeded. Initialize traversal of the process list. */ - self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer; - return 1; - } else { - /* The query failed. */ - return 0; - } - } -} - -static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self) -{ - if (self->CurrentInfo) { - if (self->CurrentInfo->NextEntryDelta > 0) { - self->CurrentInfo = ((PSYSTEM_PROCESS_INFORMATION)( - (char*)self->CurrentInfo + self->CurrentInfo->NextEntryDelta)); - return 1; - } - self->CurrentInfo = 0; - } - return 0; -} - -static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self) -{ - return self->CurrentInfo ? self->CurrentInfo->ProcessId : -1; -} - -static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self) -{ - return self->CurrentInfo ? self->CurrentInfo->InheritedFromProcessId : -1; -} - -static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self) -{ - /* Get a handle to the Windows runtime module that should already be - loaded in this program. This does not actually increment the - reference count to the module so we do not need to close the - handle. */ - HMODULE hKernel = GetModuleHandleW(L"kernel32.dll"); - if (hKernel) { - self->P_CreateToolhelp32Snapshot = - ((CreateToolhelp32SnapshotType)GetProcAddress( - hKernel, "CreateToolhelp32Snapshot")); - self->P_Process32First = - ((Process32FirstType)GetProcAddress(hKernel, "Process32First")); - self->P_Process32Next = - ((Process32NextType)GetProcAddress(hKernel, "Process32Next")); - } - return (self->P_CreateToolhelp32Snapshot && self->P_Process32First && - self->P_Process32Next) - ? 1 - : 0; -} - -static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self) -{ - if (self->Snapshot) { - CloseHandle(self->Snapshot); - } -} - -static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self) -{ - if (self->Snapshot) { - CloseHandle(self->Snapshot); - } - if (!(self->Snapshot = - self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) { - return 0; - } - ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry)); - self->CurrentEntry.dwSize = sizeof(self->CurrentEntry); - if (!self->P_Process32First(self->Snapshot, &self->CurrentEntry)) { - CloseHandle(self->Snapshot); - self->Snapshot = 0; - return 0; - } - return 1; -} - -static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self) -{ - if (self->Snapshot) { - if (self->P_Process32Next(self->Snapshot, &self->CurrentEntry)) { - return 1; - } - CloseHandle(self->Snapshot); - self->Snapshot = 0; - } - return 0; -} - -static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self) -{ - return self->Snapshot ? self->CurrentEntry.th32ProcessID : -1; -} - -static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self) -{ - return self->Snapshot ? self->CurrentEntry.th32ParentProcessID : -1; -} - -static void kwsysProcessKill(DWORD pid) -{ - HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid); - if (h) { - TerminateProcess(h, 255); - WaitForSingleObject(h, INFINITE); - CloseHandle(h); - } -} - -static void kwsysProcessKillTree(int pid) -{ - kwsysProcess_List* plist = kwsysProcess_List_New(); - kwsysProcessKill(pid); - if (plist) { - do { - if (kwsysProcess_List_GetCurrentParentId(plist) == pid) { - int ppid = kwsysProcess_List_GetCurrentProcessId(plist); - kwsysProcessKillTree(ppid); - } - } while (kwsysProcess_List_NextProcess(plist)); - kwsysProcess_List_Delete(plist); - } -} - -static void kwsysProcessDisablePipeThreads(kwsysProcess* cp) -{ - int i; - - /* If data were just reported data, release the pipe's thread. */ - if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { - KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); - cp->CurrentIndex = KWSYSPE_PIPE_COUNT; - } - - /* Wakeup all reading threads that are not on closed pipes. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - /* The wakeup threads will write one byte to the pipe write ends. - If there are no data in the pipe then this is enough to wakeup - the reading threads. If there are already data in the pipe - this may block. We cannot use PeekNamedPipe to check whether - there are data because an outside process might still be - writing data if we are disowning it. Also, PeekNamedPipe will - block if checking a pipe on which the reading thread is - currently calling ReadPipe. Therefore we need a separate - thread to call WriteFile. If it blocks, that is okay because - it will unblock when we close the read end and break the pipe - below. */ - if (cp->Pipe[i].Read) { - KWSYSPE_DEBUG((stderr, "releasing waker %d\n", i)); - ReleaseSemaphore(cp->Pipe[i].Waker.Go, 1, 0); - } - } - - /* Tell pipe threads to reset until we run another process. */ - while (cp->PipesLeft > 0) { - /* The waking threads will cause all reading threads to report. - Wait for the next one and save its index. */ - KWSYSPE_DEBUG((stderr, "waiting for reader\n")); - WaitForSingleObject(cp->Full, INFINITE); - cp->CurrentIndex = cp->SharedIndex; - ReleaseSemaphore(cp->SharedIndexMutex, 1, 0); - KWSYSPE_DEBUG((stderr, "got reader %d\n", cp->CurrentIndex)); - - /* We are done reading this pipe. Close its read handle. */ - cp->Pipe[cp->CurrentIndex].Closed = 1; - kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read); - --cp->PipesLeft; - - /* Tell the reading thread we are done with the data. It will - reset immediately because the pipe is closed. */ - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); - } -} - -/* Global set of executing processes for use by the Ctrl handler. - This global instance will be zero-initialized by the compiler. - - Note that the console Ctrl handler runs on a background thread and so - everything it does must be thread safe. Here, we track the hProcess - HANDLEs directly instead of kwsysProcess instances, so that we don't have - to make kwsysProcess thread safe. */ -typedef struct kwsysProcessInstance_s -{ - HANDLE hProcess; - DWORD dwProcessId; - int NewProcessGroup; /* Whether the process was created in a new group. */ -} kwsysProcessInstance; - -typedef struct kwsysProcessInstances_s -{ - /* Whether we have initialized key fields below, like critical sections. */ - int Initialized; - - /* Ctrl handler runs on a different thread, so we must sync access. */ - CRITICAL_SECTION Lock; - - int Exiting; - size_t Count; - size_t Size; - kwsysProcessInstance* Processes; -} kwsysProcessInstances; -static kwsysProcessInstances kwsysProcesses; - -/* Initialize critial section and set up console Ctrl handler. You MUST call - this before using any other kwsysProcesses* functions below. */ -static int kwsysProcessesInitialize(void) -{ - /* Initialize everything if not done already. */ - if (!kwsysProcesses.Initialized) { - InitializeCriticalSection(&kwsysProcesses.Lock); - - /* Set up console ctrl handler. */ - if (!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE)) { - return 0; - } - - kwsysProcesses.Initialized = 1; - } - return 1; -} - -/* The Ctrl handler waits on the global list of processes. To prevent an - orphaned process, do not create a new process if the Ctrl handler is - already running. Do so by using this function to check if it is ok to - create a process. */ -static int kwsysTryEnterCreateProcessSection(void) -{ - /* Enter main critical section; this means creating a process and the Ctrl - handler are mutually exclusive. */ - EnterCriticalSection(&kwsysProcesses.Lock); - /* Indicate to the caller if they can create a process. */ - if (kwsysProcesses.Exiting) { - LeaveCriticalSection(&kwsysProcesses.Lock); - return 0; - } else { - return 1; - } -} - -/* Matching function on successful kwsysTryEnterCreateProcessSection return. - Make sure you called kwsysProcessesAdd if applicable before calling this.*/ -static void kwsysLeaveCreateProcessSection(void) -{ - LeaveCriticalSection(&kwsysProcesses.Lock); -} - -/* Add new process to global process list. The Ctrl handler will wait for - the process to exit before it returns. Do not close the process handle - until after calling kwsysProcessesRemove. The newProcessGroup parameter - must be set if the process was created with CREATE_NEW_PROCESS_GROUP. */ -static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid, - int newProcessGroup) -{ - if (!kwsysProcessesInitialize() || !hProcess || - hProcess == INVALID_HANDLE_VALUE) { - return 0; - } - - /* Enter the critical section. */ - EnterCriticalSection(&kwsysProcesses.Lock); - - /* Make sure there is enough space for the new process handle. */ - if (kwsysProcesses.Count == kwsysProcesses.Size) { - size_t newSize; - kwsysProcessInstance* newArray; - /* Start with enough space for a small number of process handles - and double the size each time more is needed. */ - newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4; - - /* Try allocating the new block of memory. */ - if (newArray = (kwsysProcessInstance*)malloc( - newSize * sizeof(kwsysProcessInstance))) { - /* Copy the old process handles to the new memory. */ - if (kwsysProcesses.Count > 0) { - memcpy(newArray, kwsysProcesses.Processes, - kwsysProcesses.Count * sizeof(kwsysProcessInstance)); - } - } else { - /* Failed to allocate memory for the new process handle set. */ - LeaveCriticalSection(&kwsysProcesses.Lock); - return 0; - } - - /* Free original array. */ - free(kwsysProcesses.Processes); - - /* Update original structure with new allocation. */ - kwsysProcesses.Size = newSize; - kwsysProcesses.Processes = newArray; - } - - /* Append the new process information to the set. */ - kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess; - kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid; - kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup = - newProcessGroup; - - /* Leave critical section and return success. */ - LeaveCriticalSection(&kwsysProcesses.Lock); - - return 1; -} - -/* Removes process to global process list. */ -static void kwsysProcessesRemove(HANDLE hProcess) -{ - size_t i; - - if (!hProcess || hProcess == INVALID_HANDLE_VALUE) { - return; - } - - EnterCriticalSection(&kwsysProcesses.Lock); - - /* Find the given process in the set. */ - for (i = 0; i < kwsysProcesses.Count; ++i) { - if (kwsysProcesses.Processes[i].hProcess == hProcess) { - break; - } - } - if (i < kwsysProcesses.Count) { - /* Found it! Remove the process from the set. */ - --kwsysProcesses.Count; - for (; i < kwsysProcesses.Count; ++i) { - kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i + 1]; - } - - /* If this was the last process, free the array. */ - if (kwsysProcesses.Count == 0) { - kwsysProcesses.Size = 0; - free(kwsysProcesses.Processes); - kwsysProcesses.Processes = 0; - } - } - - LeaveCriticalSection(&kwsysProcesses.Lock); -} - -static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType) -{ - size_t i; - (void)dwCtrlType; - /* Enter critical section. */ - EnterCriticalSection(&kwsysProcesses.Lock); - - /* Set flag indicating that we are exiting. */ - kwsysProcesses.Exiting = 1; - - /* If some of our processes were created in a new process group, we must - manually interrupt them. They won't otherwise receive a Ctrl+C/Break. */ - for (i = 0; i < kwsysProcesses.Count; ++i) { - if (kwsysProcesses.Processes[i].NewProcessGroup) { - DWORD groupId = kwsysProcesses.Processes[i].dwProcessId; - if (groupId) { - GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId); - } - } - } - - /* Wait for each child process to exit. This is the key step that prevents - us from leaving several orphaned children processes running in the - background when the user presses Ctrl+C. */ - for (i = 0; i < kwsysProcesses.Count; ++i) { - WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE); - } - - /* Leave critical section. */ - LeaveCriticalSection(&kwsysProcesses.Lock); - - /* Continue on to default Ctrl handler (which calls ExitProcess). */ - return FALSE; -} - -void kwsysProcess_ResetStartTime(kwsysProcess* cp) -{ - if (!cp) { - return; - } - /* Reset start time. */ - cp->StartTime = kwsysProcessTimeGetCurrent(); -} diff --git a/thirdparty/KWSys/adios2sys/README.rst b/thirdparty/KWSys/adios2sys/README.rst deleted file mode 100644 index fc6b5902ed..0000000000 --- a/thirdparty/KWSys/adios2sys/README.rst +++ /dev/null @@ -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 diff --git a/thirdparty/KWSys/adios2sys/RegularExpression.cxx b/thirdparty/KWSys/adios2sys/RegularExpression.cxx deleted file mode 100644 index 78cff1a01e..0000000000 --- a/thirdparty/KWSys/adios2sys/RegularExpression.cxx +++ /dev/null @@ -1,1216 +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 -#include - -namespace KWSYS_NAMESPACE { - -// RegularExpression -- Copies the given regular expression. -RegularExpression::RegularExpression(const RegularExpression& rxp) -{ - if (!rxp.program) { - this->program = KWSYS_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 != KWSYS_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 = KWSYS_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 != KWSYS_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 NULL - * regmlen length of regmust string - * - * Regstart and reganch permit very fast decisions on suitable starting points - * for a match, cutting down the work a lot. Regmust permits fast rejection - * of lines that cannot possibly match. The regmust tests are costly enough - * that compile() supplies a regmust only if the r.e. contains something - * potentially expensive (at present, the only such thing detected is * or + - * at the start of the r.e., which can involve a lot of backup). Regmlen is - * supplied because the test in find() needs it and compile() is computing - * it anyway. - */ - -/* - * Structure for regexp "program". This is essentially a linear encoding - * of a nondeterministic finite-state machine (aka syntax charts or - * "railroad normal form" in parsing technology). Each node is an opcode - * plus a "next" pointer, possibly plus an operand. "Next" pointers of - * all nodes except BRANCH implement concatenation; a "next" pointer with - * a BRANCH on both ends of it is connecting two alternatives. (Here we - * have one of the subtle syntax dependencies: an individual BRANCH (as - * opposed to a collection of them) is never concatenated with anything - * because of operator precedence.) The operand of some types of node is - * a literal string; for others, it is a node leading into a sub-FSM. In - * particular, the operand of a BRANCH node is the first node of the branch. - * (NB this is *not* a tree structure: the tail of the branch connects - * to the thing following the set of BRANCHes.) The opcodes are: - */ - -// definition number opnd? meaning -#define END 0 // no End of program. -#define BOL 1 // no Match "" at beginning of line. -#define EOL 2 // no Match "" at end of line. -#define ANY 3 // no Match any one character. -#define ANYOF 4 // str Match any character in this string. -#define ANYBUT 5 // str Match any character not in this - // string. -#define BRANCH 6 // node Match this alternative, or the - // next... -#define BACK 7 // no Match "", "next" ptr points backward. -#define EXACTLY 8 // str Match this string. -#define NOTHING 9 // no Match empty string. -#define STAR 10 // node Match this (simple) thing 0 or more - // times. -#define PLUS 11 // node Match this (simple) thing 1 or more - // times. -#define OPEN 20 // no Mark this point in input as start of - // #n. -// OPEN+1 is number 1, etc. -#define CLOSE 30 // no Analogous to OPEN. - -/* - * Opcode notes: - * - * BRANCH The set of branches constituting a single choice are hooked - * together with their "next" pointers, since precedence prevents - * anything being concatenated to any individual branch. The - * "next" pointer of the last BRANCH in a choice points to the - * thing following the whole choice. This is also where the - * final "next" pointer of each individual branch points; each - * branch starts with the operand node of a BRANCH node. - * - * BACK Normal "next" pointers all implicitly point forward; BACK - * exists to make loop structures possible. - * - * STAR,PLUS '?', and complex '*' and '+', are implemented as circular - * BRANCH structures using BACK. Simple cases (one character - * per match) are implemented with STAR and PLUS for speed - * and to minimize recursive plunges. - * - * OPEN,CLOSE ...are numbered at compile time. - */ - -/* - * A node is one char of opcode followed by two chars of "next" pointer. - * "Next" pointers are stored as two 8-bit pieces, high order first. The - * value is a positive offset from the opcode of the node containing it. - * An operand, if any, simply follows the node. (Note that much of the - * code generation knows about this implicit relationship.) - * - * Using two bytes for the "next" pointer is vast overkill for most things, - * but allows patterns to get big without disasters. - */ - -#define OP(p) (*(p)) -#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377)) -#define OPERAND(p) ((p) + 3) - -const unsigned char MAGIC = 0234; -/* - * Utility definitions. - */ - -#define UCHARAT(p) (reinterpret_cast(p))[0] - -#define 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; - size_t len; - int flags; - - if (exp == KWSYS_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(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 != KWSYS_NULLPTR) - delete[] this->program; - //#endif - this->program = new char[comp.regsize]; - this->progsize = static_cast(comp.regsize); - - if (this->program == KWSYS_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(MAGIC)); - comp.reg(0, &flags); - - // Dig out information for optimizations. - this->regstart = '\0'; // Worst-case defaults. - this->reganch = 0; - this->regmust = KWSYS_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 = KWSYS_NULLPTR; - len = 0; - for (; scan != KWSYS_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 KWSYS_NULLPTR; - } - parno = regnpar; - regnpar++; - ret = regnode(static_cast(OPEN + parno)); - } else - ret = KWSYS_NULLPTR; - - // Pick up the branches, linking them together. - br = regbranch(&flags); - if (br == KWSYS_NULLPTR) - return (KWSYS_NULLPTR); - if (ret != KWSYS_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 == KWSYS_NULLPTR) - return (KWSYS_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((paren) ? CLOSE + parno : END)); - regtail(ret, ender); - - // Hook the tails of the branches to the closing node. - for (br = ret; br != KWSYS_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 KWSYS_NULLPTR; - } else if (!paren && *regparse != '\0') { - if (*regparse == ')') { - // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens), - printf("RegularExpression::compile(): Unmatched parentheses.\n"); - return KWSYS_NULLPTR; - } else { - // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), - printf("RegularExpression::compile(): Internal error.\n"); - return KWSYS_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 = KWSYS_NULLPTR; - while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { - latest = regpiece(&flags); - if (latest == KWSYS_NULLPTR) - return (KWSYS_NULLPTR); - *flagp |= flags & HASWIDTH; - if (chain == KWSYS_NULLPTR) // First piece. - *flagp |= flags & SPSTART; - else - regtail(chain, latest); - chain = latest; - } - if (chain == KWSYS_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 == KWSYS_NULLPTR) - return (KWSYS_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 KWSYS_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 KWSYS_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 KWSYS_NULLPTR; - } - for (; rxpclass <= rxpclassend; rxpclass++) - regc(static_cast(rxpclass)); - regparse++; - } - } else - regc(*regparse++); - } - regc('\0'); - if (*regparse != ']') { - // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket), - printf("RegularExpression::compile(): Unmatched [].\n"); - return KWSYS_NULLPTR; - } - regparse++; - *flagp |= HASWIDTH | SIMPLE; - } break; - case '(': - ret = reg(1, &flags); - if (ret == KWSYS_NULLPTR) - return (KWSYS_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 KWSYS_NULLPTR; - case '?': - case '+': - case '*': - // RAISE Error, SYM(RegularExpression), SYM(No_Operand), - printf("RegularExpression::compile(): ?+* follows nothing.\n"); - return KWSYS_NULLPTR; - case '\\': - if (*regparse == '\0') { - // RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash), - printf("RegularExpression::compile(): Trailing backslash.\n"); - return KWSYS_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 KWSYS_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 == KWSYS_NULLPTR) - break; - scan = temp; - } - - if (OP(scan) == BACK) - offset = int(scan - val); - else - offset = int(val - scan); - *(scan + 1) = static_cast((offset >> 8) & 0377); - *(scan + 2) = static_cast(offset & 0377); -} - -/* - - regoptail - regtail on operand of first argument; nop if operandless - */ -void RegExpCompile::regoptail(char* p, const char* val) -{ - // "Operandless" and "op != BRANCH" are synonymous in practice. - if (p == KWSYS_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 != KWSYS_NULLPTR) { - s = string; - while ((s = strchr(s, this->regmust[0])) != KWSYS_NULLPTR) { - if (strncmp(s, this->regmust, this->regmlen) == 0) - break; // Found it. - s++; - } - if (s == KWSYS_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)) != KWSYS_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++ = KWSYS_NULLPTR; - *ep++ = KWSYS_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 != KWSYS_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) == KWSYS_NULLPTR) - return (0); - reginput++; - break; - case ANYBUT: - if (*reginput == '\0' || - strchr(OPERAND(scan), *reginput) != KWSYS_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] == KWSYS_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] == KWSYS_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 != KWSYS_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) != KWSYS_NULLPTR) { - count++; - scan++; - } - break; - case ANYBUT: - while (*scan != '\0' && strchr(opnd, *scan) == KWSYS_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 (KWSYS_NULLPTR); - - offset = NEXT(p); - if (offset == 0) - return (KWSYS_NULLPTR); - - if (OP(p) == BACK) - return (p - offset); - else - return (p + offset); -} - -static char* regnext(char* p) -{ - int offset; - - if (p == regdummyptr) - return (KWSYS_NULLPTR); - - offset = NEXT(p); - if (offset == 0) - return (KWSYS_NULLPTR); - - if (OP(p) == BACK) - return (p - offset); - else - return (p + offset); -} - -} // namespace KWSYS_NAMESPACE diff --git a/thirdparty/KWSys/adios2sys/RegularExpression.hxx.in b/thirdparty/KWSys/adios2sys/RegularExpression.hxx.in deleted file mode 100644 index 3cbbeb8b6f..0000000000 --- a/thirdparty/KWSys/adios2sys/RegularExpression.hxx.in +++ /dev/null @@ -1,548 +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 - -/* 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[0] = 0; - endp[0] = 0; - searchstring = 0; -} - -/** - * \brief Returns true if the match pointers are valid - */ -inline bool RegularExpressionMatch::isValid() const -{ - return (this->startp[0] != 0); -} - -/** - * \brief Resets to the (invalid) construction state. - */ -inline void RegularExpressionMatch::clear() -{ - startp[0] = 0; - endp[0] = 0; - searchstring = 0; -} - -/** - * \brief Returns the start index of the full match. - */ -inline std::string::size_type RegularExpressionMatch::start() const -{ - return static_cast(this->startp[0] - searchstring); -} - -/** - * \brief Returns the end index of the full match. - */ -inline std::string::size_type RegularExpressionMatch::end() const -{ - return static_cast(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(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(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] == 0) { - return std::string(); - } else { - return std::string(this->startp[n], static_cast( - 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 NULL, - * (i.e. there is no valid compiled exression). The set_invalid function sets - * the program to NULL (Warning: this deletes the compiled expression). The - * following examples may help clarify regular expression usage: - * - * * The regular expression "^hello" matches a "hello" only at the - * beginning of a line. It would match "hello there" but not "hi, - * hello there". - * - * * The regular expression "long$" matches a "long" only at the end - * of a line. It would match "so long\0", but not "long ago". - * - * * The regular expression "t..t..g" will match anything that has a - * "t" then any two characters, another "t", any two characters and - * then a "g". It will match "testing", or "test again" but would - * not match "toasting" - * - * * The regular expression "[1-9ab]" matches any number one through - * nine, and the characters "a" and "b". It would match "hello 1" - * or "begin", but would not match "no-match". - * - * * The regular expression "[^1-9ab]" matches any character that is - * not a number one through nine, or an "a" or "b". It would NOT - * match "hello 1" or "begin", but would match "no-match". - * - * * The regular expression "br* " matches something that begins with - * a "b", is followed by zero or more "r"s, and ends in a space. It - * would match "brrrrr ", and "b ", but would not match "brrh ". - * - * * The regular expression "br+ " matches something that begins with - * a "b", is followed by one or more "r"s, and ends in a space. It - * would match "brrrrr ", and "br ", but would not match "b " or - * "brrh ". - * - * * The regular expression "br? " matches something that begins with - * a "b", is followed by zero or one "r"s, and ends in a space. It - * would match "br ", and "b ", but would not match "brrrr " or - * "brrh ". - * - * * The regular expression "(..p)b" matches something ending with pb - * and beginning with whatever the two characters before the first p - * encounterd in the line were. It would find "repb" in "rep drepa - * qrepb". The regular expression "(..p)a" would find "repa qrepb" - * in "rep drepa qrepb" - * - * * The regular expression "d(..p)" matches something ending with p, - * beginning with d, and having two characters in between that are - * the same as the two characters before the first p encounterd in - * the line. It would match "drepa qrepb" in "rep drepa qrepb". - * - * 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=NULL. - */ - inline RegularExpression(); - - /** - * Instantiate RegularExpression with compiled char*. - */ - inline RegularExpression(char const*); - - /** - * Instantiate RegularExpression as a copy of another regular expression. - */ - RegularExpression(RegularExpression const&); - - /** - * Instantiate RegularExpression with compiled string. - */ - inline RegularExpression(std::string const&); - - /** - * Destructor. - */ - inline ~RegularExpression(); - - /** - * Compile a regular expression into internal code - * for later pattern matching. - */ - bool compile(char const*); - - /** - * Compile a regular expression into internal code - * for later pattern matching. - */ - inline bool compile(std::string const&); - - /** - * Matches the regular expression to the given string. - * Returns true if found, and sets start and end indexes - * 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() -{ - this->program = 0; -} - -/** - * Creates a regular expression from string s, and - * compiles s. - */ -inline RegularExpression::RegularExpression(const char* s) -{ - this->program = 0; - if (s) { - this->compile(s); - } -} - -/** - * Creates a regular expression from string s, and - * compiles s. - */ -inline RegularExpression::RegularExpression(const std::string& s) -{ - this->program = 0; - this->compile(s); -} - -/** - * Destroys and frees space allocated for the regular expression. - */ -inline RegularExpression::~RegularExpression() -{ - //#ifndef _WIN32 - delete[] this->program; - //#endif -} - -/** - * Compile a regular expression into internal code - * for later pattern matching. - */ -inline bool RegularExpression::compile(std::string const& s) -{ - return this->compile(s.c_str()); -} - -/** - * Matches the regular expression to the given std string. - * Returns true if found, and sets start and end indexes accordingly. - */ -inline bool RegularExpression::find(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 != 0); -} - -inline void RegularExpression::set_invalid() -{ - //#ifndef _WIN32 - delete[] this->program; - //#endif - this->program = 0; -} - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/SharedForward.h.in b/thirdparty/KWSys/adios2sys/SharedForward.h.in deleted file mode 100644 index 0caf5e7c3f..0000000000 --- a/thirdparty/KWSys/adios2sys/SharedForward.h.in +++ /dev/null @@ -1,876 +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 -#include -#include /* size_t */ -#include -#include -#include - -#if defined(_WIN32) && !defined(__CYGWIN__) -#include - -#include -#include -#define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */ -#else -#include -#include -#endif - -/* Configuration for this platform. */ - -/* The path separator for this platform. */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#define KWSYS_SHARED_FORWARD_PATH_SEP ';' -#define KWSYS_SHARED_FORWARD_PATH_SLASH '\\' -#else -#define KWSYS_SHARED_FORWARD_PATH_SEP ':' -#define KWSYS_SHARED_FORWARD_PATH_SLASH '/' -#endif -static const char kwsys_shared_forward_path_sep[2] = { - KWSYS_SHARED_FORWARD_PATH_SEP, 0 -}; -static const char kwsys_shared_forward_path_slash[2] = { - KWSYS_SHARED_FORWARD_PATH_SLASH, 0 -}; - -/* The maximum length of a file name. */ -#if defined(PATH_MAX) -#define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX -#elif defined(MAXPATHLEN) -#define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN -#else -#define KWSYS_SHARED_FORWARD_MAXPATH 16384 -#endif - -/* Select the environment variable holding the shared library runtime - search path for this platform and build configuration. Also select - ldd command equivalent. */ - -/* Linux */ -#if defined(__linux) -#define KWSYS_SHARED_FORWARD_LDD "ldd" -#define KWSYS_SHARED_FORWARD_LDD_N 1 -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" - -/* FreeBSD */ -#elif defined(__FreeBSD__) -#define KWSYS_SHARED_FORWARD_LDD "ldd" -#define KWSYS_SHARED_FORWARD_LDD_N 1 -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" - -/* OpenBSD */ -#elif defined(__OpenBSD__) -#define KWSYS_SHARED_FORWARD_LDD "ldd" -#define KWSYS_SHARED_FORWARD_LDD_N 1 -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" - -/* 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 -#if defined(_ILP32) -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -#elif defined(_LP64) -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64" -#endif - -/* HP-UX */ -#elif defined(__hpux) -#define KWSYS_SHARED_FORWARD_LDD "chatr" -#define KWSYS_SHARED_FORWARD_LDD_N 1 -#if defined(__LP64__) -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -#else -#define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH" -#endif - -/* SGI MIPS */ -#elif defined(__sgi) && defined(_MIPS_SIM) -#define KWSYS_SHARED_FORWARD_LDD "ldd" -#define KWSYS_SHARED_FORWARD_LDD_N 1 -#if _MIPS_SIM == _ABIO32 -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -#elif _MIPS_SIM == _ABIN32 -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH" -#elif _MIPS_SIM == _ABI64 -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH" -#endif - -/* Cygwin */ -#elif defined(__CYGWIN__) -#define KWSYS_SHARED_FORWARD_LDD "cygcheck" /* TODO: cygwin 1.7 has ldd */ -#define KWSYS_SHARED_FORWARD_LDD_N 1 -#define KWSYS_SHARED_FORWARD_LDPATH "PATH" - -/* Windows */ -#elif defined(_WIN32) -#define KWSYS_SHARED_FORWARD_LDPATH "PATH" - -/* Guess on this unknown system. */ -#else -#define KWSYS_SHARED_FORWARD_LDD "ldd" -#define KWSYS_SHARED_FORWARD_LDD_N 1 -#define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -#endif - -#ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV -typedef struct kwsys_sf_arg_info_s -{ - const char* arg; - int size; - int quote; -} kwsys_sf_arg_info; - -static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in) -{ - /* Initialize information. */ - kwsys_sf_arg_info info; - - /* String iterator. */ - const char* c; - - /* Keep track of how many backslashes have been encountered in a row. */ - int windows_backslashes = 0; - - /* Start with the length of the original argument, plus one for - either a terminating null or a separating space. */ - info.arg = in; - info.size = (int)strlen(in) + 1; - info.quote = 0; - - /* Scan the string for characters that require escaping or quoting. */ - for (c = in; *c; ++c) { - /* Check whether this character needs quotes. */ - if (strchr(" \t?'#&<>|^", *c)) { - info.quote = 1; - } - - /* On Windows only backslashes and double-quotes need escaping. */ - if (*c == '\\') { - /* Found a backslash. It may need to be escaped later. */ - ++windows_backslashes; - } else if (*c == '"') { - /* Found a double-quote. We need to escape it and all - immediately preceding backslashes. */ - info.size += windows_backslashes + 1; - windows_backslashes = 0; - } else { - /* Found another character. This eliminates the possibility - that any immediately preceding backslashes will be - escaped. */ - windows_backslashes = 0; - } - } - - /* Check whether the argument needs surrounding quotes. */ - if (info.quote) { - /* Surrounding quotes are needed. Allocate space for them. */ - info.size += 2; - - /* We must escape all ending backslashes when quoting on windows. */ - info.size += windows_backslashes; - } - - return info; -} - -static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out) -{ - /* String iterator. */ - const char* c; - - /* Keep track of how many backslashes have been encountered in a row. */ - int windows_backslashes = 0; - - /* Whether the argument must be quoted. */ - if (info.quote) { - /* Add the opening quote for this argument. */ - *out++ = '"'; - } - - /* Scan the string for characters that require escaping or quoting. */ - for (c = info.arg; *c; ++c) { - /* On Windows only backslashes and double-quotes need escaping. */ - if (*c == '\\') { - /* Found a backslash. It may need to be escaped later. */ - ++windows_backslashes; - } else if (*c == '"') { - /* Found a double-quote. Escape all immediately preceding - backslashes. */ - while (windows_backslashes > 0) { - --windows_backslashes; - *out++ = '\\'; - } - - /* Add the backslash to escape the double-quote. */ - *out++ = '\\'; - } else { - /* We encountered a normal character. This eliminates any - escaping needed for preceding backslashes. */ - windows_backslashes = 0; - } - - /* Store this character. */ - *out++ = *c; - } - - if (info.quote) { - /* Add enough backslashes to escape any trailing ones. */ - while (windows_backslashes > 0) { - --windows_backslashes; - *out++ = '\\'; - } - - /* Add the closing quote for this argument. */ - *out++ = '"'; - } - - /* Store a terminating null without incrementing. */ - *out = 0; - - return out; -} -#endif - -/* Function to convert a logical or relative path to a physical full path. */ -static int kwsys_shared_forward_realpath(const char* in_path, char* out_path) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Implementation for Windows. */ - DWORD n = - GetFullPathNameA(in_path, KWSYS_SHARED_FORWARD_MAXPATH, out_path, 0); - return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH; -#else - /* Implementation for UNIX. */ - return realpath(in_path, out_path) != 0; -#endif -} - -static int kwsys_shared_forward_samepath(const char* file1, const char* file2) -{ -#if defined(_WIN32) - int result = 0; - HANDLE h1 = CreateFileA(file1, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - HANDLE h2 = CreateFileA(file2, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE) { - BY_HANDLE_FILE_INFORMATION fi1; - BY_HANDLE_FILE_INFORMATION fi2; - GetFileInformationByHandle(h1, &fi1); - GetFileInformationByHandle(h2, &fi2); - result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber && - fi1.nFileIndexHigh == fi2.nFileIndexHigh && - fi1.nFileIndexLow == fi2.nFileIndexLow); - } - CloseHandle(h1); - CloseHandle(h2); - return result; -#else - struct stat fs1, fs2; - return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 && - memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 && - memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 && - fs2.st_size == fs1.st_size); -#endif -} - -/* Function to report a system error message. */ -static void kwsys_shared_forward_strerror(char* message) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Implementation for Windows. */ - DWORD original = GetLastError(); - DWORD length = - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0, original, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - message, KWSYS_SHARED_FORWARD_MAXPATH, 0); - if (length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) { - /* FormatMessage failed. Use a default message. */ - _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH, - "Error 0x%X (FormatMessage failed with error 0x%X)", original, - GetLastError()); - } -#else - /* Implementation for UNIX. */ - strcpy(message, strerror(errno)); -#endif -} - -/* Functions to execute a child process. */ -static void kwsys_shared_forward_execvp(const char* cmd, - char const* const* argv) -{ -#ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV - /* Count the number of arguments. */ - int argc = 0; - { - char const* const* argvc; - for (argvc = argv; *argvc; ++argvc, ++argc) { - } - } - - /* Create the escaped arguments. */ - { - char** nargv = (char**)malloc((argc + 1) * sizeof(char*)); - int i; - for (i = 0; i < argc; ++i) { - kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]); - nargv[i] = (char*)malloc(info.size); - kwsys_sf_get_arg(info, nargv[i]); - } - nargv[argc] = 0; - - /* Replace the command line to be used. */ - argv = (char const* const*)nargv; - } -#endif - -/* Invoke the child process. */ -#if defined(_MSC_VER) - _execvp(cmd, argv); -#elif defined(__MINGW32__) && !defined(__MINGW64__) - execvp(cmd, argv); -#else - execvp(cmd, (char* const*)argv); -#endif -} - -/* Function to get the directory containing the given file or directory. */ -static void kwsys_shared_forward_dirname(const char* begin, char* result) -{ - /* Find the location of the last slash. */ - int last_slash_index = -1; - const char* end = begin + strlen(begin); - for (; begin <= end && last_slash_index < 0; --end) { - if (*end == '/' || *end == '\\') { - last_slash_index = (int)(end - begin); - } - } - - /* Handle each case of the index of the last slash. */ - if (last_slash_index < 0) { - /* No slashes. */ - strcpy(result, "."); - } else if (last_slash_index == 0) { - /* Only one leading slash. */ - strcpy(result, kwsys_shared_forward_path_slash); - } -#if defined(_WIN32) - else if (last_slash_index == 2 && begin[1] == ':') { - /* Only one leading drive letter and slash. */ - strncpy(result, begin, (size_t)last_slash_index); - result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH; - result[last_slash_index + 1] = 0; - } -#endif - else { - /* A non-leading slash. */ - strncpy(result, begin, (size_t)last_slash_index); - result[last_slash_index] = 0; - } -} - -/* Function to check if a file exists and is executable. */ -static int kwsys_shared_forward_is_executable(const char* f) -{ -#if defined(_MSC_VER) -#define KWSYS_SHARED_FORWARD_ACCESS _access -#else -#define KWSYS_SHARED_FORWARD_ACCESS access -#endif -#if defined(X_OK) -#define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK -#else -#define KWSYS_SHARED_FORWARD_ACCESS_OK 04 -#endif - if (KWSYS_SHARED_FORWARD_ACCESS(f, KWSYS_SHARED_FORWARD_ACCESS_OK) == 0) { - return 1; - } else { - return 0; - } -} - -/* Function to locate the executable currently running. */ -static int kwsys_shared_forward_self_path(const char* argv0, char* result) -{ - /* Check whether argv0 has a slash. */ - int has_slash = 0; - const char* p = argv0; - for (; *p && !has_slash; ++p) { - if (*p == '/' || *p == '\\') { - has_slash = 1; - } - } - - if (has_slash) { - /* There is a slash. Use the dirname of the given location. */ - kwsys_shared_forward_dirname(argv0, result); - return 1; - } else { - /* There is no slash. Search the PATH for the executable. */ - const char* path = getenv("PATH"); - const char* begin = path; - const char* end = begin + (begin ? strlen(begin) : 0); - const char* first = begin; - while (first != end) { - /* Store the end of this path entry. */ - const char* last; - - /* Skip all path separators. */ - for (; *first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first) - ; - - /* Find the next separator. */ - for (last = first; *last && *last != KWSYS_SHARED_FORWARD_PATH_SEP; - ++last) - ; - - /* If we got a non-empty directory, look for the executable there. */ - if (first < last) { - /* Determine the length without trailing slash. */ - size_t length = (size_t)(last - first); - if (*(last - 1) == '/' || *(last - 1) == '\\') { - --length; - } - - /* Construct the name of the executable in this location. */ - strncpy(result, first, length); - result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH; - strcpy(result + (length) + 1, argv0); - - /* Check if it exists and is executable. */ - if (kwsys_shared_forward_is_executable(result)) { - /* Found it. */ - result[length] = 0; - return 1; - } - } - - /* Move to the next directory in the path. */ - first = last; - } - } - - /* We could not find the executable. */ - return 0; -} - -/* Function to convert a specified path to a full path. If it is not - already full, it is taken relative to the self path. */ -static int kwsys_shared_forward_fullpath(const char* self_path, - const char* in_path, char* result, - const char* desc) -{ - /* Check the specified path type. */ - if (in_path[0] == '/') { - /* Already a full path. */ - strcpy(result, in_path); - } -#if defined(_WIN32) - else if (in_path[0] && in_path[1] == ':') { - /* Already a full path. */ - strcpy(result, in_path); - } -#endif - else { - /* Relative to self path. */ - char temp_path[KWSYS_SHARED_FORWARD_MAXPATH]; - strcpy(temp_path, self_path); - strcat(temp_path, kwsys_shared_forward_path_slash); - strcat(temp_path, in_path); - if (!kwsys_shared_forward_realpath(temp_path, result)) { - if (desc) { - char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; - kwsys_shared_forward_strerror(msgbuf); - fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", desc, - temp_path, msgbuf); - } - return 0; - } - } - return 1; -} - -/* Function to compute the library search path and executable name - based on the self path. */ -static int kwsys_shared_forward_get_settings(const char* self_path, - char* ldpath, char* exe) -{ - /* Possible search paths. */ - static const char* search_path_build[] = { KWSYS_SHARED_FORWARD_PATH_BUILD, - 0 }; - static const char* search_path_install[] = { - KWSYS_SHARED_FORWARD_PATH_INSTALL, 0 - }; - - /* Chosen paths. */ - const char** search_path; - const char* exe_path; - -/* Get the real name of the build and self paths. */ -#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) - char build_path[] = - KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME; - char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH]; -#else - char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD; - const char* self_path_logical = self_path; -#endif - char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; - char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; - if (!kwsys_shared_forward_realpath(self_path, self_path_real)) { - char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; - kwsys_shared_forward_strerror(msgbuf); - fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n", - self_path, msgbuf); - return 0; - } - - /* Check whether we are running in the build tree or an install tree. */ - if (kwsys_shared_forward_realpath(build_path, build_path_real) && - kwsys_shared_forward_samepath(self_path_real, build_path_real)) { - /* Running in build tree. Use the build path and exe. */ - search_path = search_path_build; -#if defined(_WIN32) - exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe"; -#else - exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD; -#endif - -#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) - /* Remove the configuration directory from self_path. */ - kwsys_shared_forward_dirname(self_path, self_path_logical); -#endif - } else { - /* Running in install tree. Use the install path and exe. */ - search_path = search_path_install; -#if defined(_WIN32) - exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe"; -#else - exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL; -#endif - -#if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) - /* Use the original self path directory. */ - strcpy(self_path_logical, self_path); -#endif - } - - /* Construct the runtime search path. */ - { - const char** dir; - for (dir = search_path; *dir; ++dir) { - /* Add separator between path components. */ - if (dir != search_path) { - strcat(ldpath, kwsys_shared_forward_path_sep); - } - - /* Add this path component. */ - if (!kwsys_shared_forward_fullpath(self_path_logical, *dir, - ldpath + strlen(ldpath), - "runtime path entry")) { - return 0; - } - } - } - - /* Construct the executable location. */ - if (!kwsys_shared_forward_fullpath(self_path_logical, exe_path, exe, - "executable file")) { - return 0; - } - return 1; -} - -/* Function to print why execution of a command line failed. */ -static void kwsys_shared_forward_print_failure(char const* const* argv) -{ - char msg[KWSYS_SHARED_FORWARD_MAXPATH]; - char const* const* arg = argv; - kwsys_shared_forward_strerror(msg); - fprintf(stderr, "Error running"); - for (; *arg; ++arg) { - fprintf(stderr, " \"%s\"", *arg); - } - fprintf(stderr, ": %s\n", msg); -} - -/* Static storage space to store the updated environment variable. */ -static char kwsys_shared_forward_ldpath[65535] = - KWSYS_SHARED_FORWARD_LDPATH "="; - -/* Main driver function to be called from main. */ -static int @KWSYS_NAMESPACE@_shared_forward_to_real(int argc, char** argv_in) -{ - char const** argv = (char const**)argv_in; - /* Get the directory containing this executable. */ - char self_path[KWSYS_SHARED_FORWARD_MAXPATH]; - if (kwsys_shared_forward_self_path(argv[0], self_path)) { - /* Found this executable. Use it to get the library directory. */ - char exe[KWSYS_SHARED_FORWARD_MAXPATH]; - if (kwsys_shared_forward_get_settings(self_path, - kwsys_shared_forward_ldpath, exe)) { - /* Append the old runtime search path. */ - const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH); - if (old_ldpath) { - strcat(kwsys_shared_forward_ldpath, kwsys_shared_forward_path_sep); - strcat(kwsys_shared_forward_ldpath, old_ldpath); - } - - /* Store the environment variable. */ - putenv(kwsys_shared_forward_ldpath); - -#if defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND) - /* Look for the command line replacement option. */ - if (argc > 1 && - strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0) { - if (argc > 2) { - /* Use the command line given. */ - strcpy(exe, argv[2]); - argv += 2; - argc -= 2; - } else { - /* The option was not given an executable. */ - fprintf(stderr, "Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND - " must be followed by a command line.\n"); - return 1; - } - } -#endif - -#if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT) - /* Look for the print command line option. */ - if (argc > 1 && - strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0) { - fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath); - fprintf(stdout, "%s\n", exe); - return 0; - } -#endif - -#if defined(KWSYS_SHARED_FORWARD_OPTION_LDD) - /* Look for the ldd command line option. */ - if (argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0) { -#if defined(KWSYS_SHARED_FORWARD_LDD) - /* Use the named ldd-like executable and arguments. */ - char const* ldd_argv[] = { KWSYS_SHARED_FORWARD_LDD, 0, 0 }; - ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe; - kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv); - - /* Report why execution failed. */ - kwsys_shared_forward_print_failure(ldd_argv); - return 1; -#else - /* We have no ldd-like executable available on this platform. */ - fprintf(stderr, "No ldd-like tool is known to this executable.\n"); - return 1; -#endif - } -#endif - - /* Replace this process with the real executable. */ - argv[0] = exe; - kwsys_shared_forward_execvp(argv[0], argv); - - /* Report why execution failed. */ - kwsys_shared_forward_print_failure(argv); - } else { - /* Could not convert self path to the library directory. */ - } - } else { - /* Could not find this executable. */ - fprintf(stderr, "Error locating executable \"%s\".\n", argv[0]); - } - - /* Avoid unused argument warning. */ - (void)argc; - - /* Exit with failure. */ - return 1; -} - -/* Restore warning stack. */ -#if defined(__clang__) && defined(__has_warning) -#if __has_warning("-Wcast-qual") -#pragma clang diagnostic pop -#endif -#endif - -#else -#error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once." -#endif diff --git a/thirdparty/KWSys/adios2sys/String.c b/thirdparty/KWSys/adios2sys/String.c deleted file mode 100644 index 048222968c..0000000000 --- a/thirdparty/KWSys/adios2sys/String.c +++ /dev/null @@ -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 -#elif defined(__GNUC__) -#define KWSYS_STRING_USE_STRCASECMP -#include -#else -/* Table to convert upper case letters to lower case and leave all - other characters alone. */ -static char kwsysString_strcasecmp_tolower[] = { - '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', - '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', - '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', - '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043', - '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054', - '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065', - '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076', - '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', - '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', - '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', - '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142', - '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', - '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', - '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175', - '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', - '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', - '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', - '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', - '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', - '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', - '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', - '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', - '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', - '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', - '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', - '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', - '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', - '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', - '\374', '\375', '\376', '\377' -}; -#endif - -/*--------------------------------------------------------------------------*/ -int kwsysString_strcasecmp(const char* lhs, const char* rhs) -{ -#if defined(KWSYS_STRING_USE_STRICMP) - return _stricmp(lhs, rhs); -#elif defined(KWSYS_STRING_USE_STRCASECMP) - return strcasecmp(lhs, rhs); -#else - const char* const lower = kwsysString_strcasecmp_tolower; - unsigned char const* us1 = (unsigned char const*)lhs; - unsigned char const* us2 = (unsigned char const*)rhs; - int result; - while ((result = lower[*us1] - lower[*us2++], result == 0) && *us1++) { - } - return result; -#endif -} - -/*--------------------------------------------------------------------------*/ -int kwsysString_strncasecmp(const char* lhs, const char* rhs, size_t n) -{ -#if defined(KWSYS_STRING_USE_STRICMP) - return _strnicmp(lhs, rhs, n); -#elif defined(KWSYS_STRING_USE_STRCASECMP) - return strncasecmp(lhs, rhs, n); -#else - const char* const lower = kwsysString_strcasecmp_tolower; - unsigned char const* us1 = (unsigned char const*)lhs; - unsigned char const* us2 = (unsigned char const*)rhs; - int result = 0; - while (n && (result = lower[*us1] - lower[*us2++], result == 0) && *us1++) { - --n; - } - return result; -#endif -} - -#endif /* KWSYS_STRING_C */ diff --git a/thirdparty/KWSys/adios2sys/String.h.in b/thirdparty/KWSys/adios2sys/String.h.in deleted file mode 100644 index 3c1d571c00..0000000000 --- a/thirdparty/KWSys/adios2sys/String.h.in +++ /dev/null @@ -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 /* size_t */ - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -#define kwsys_ns(x) @KWSYS_NAMESPACE@##x -#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#define kwsysString_strcasecmp kwsys_ns(String_strcasecmp) -#define kwsysString_strncasecmp kwsys_ns(String_strncasecmp) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Compare two strings ignoring the case of the characters. The - * integer returned is negative, zero, or positive if the first string - * is found to be less than, equal to, or greater than the second - * string, respectively. - */ -kwsysEXPORT int kwsysString_strcasecmp(const char* lhs, const char* rhs); - -/** - * Identical to String_strcasecmp except that only the first n - * characters are considered. - */ -kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs, - size_t n); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -#undef kwsys_ns -#undef kwsysEXPORT -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#undef kwsysString_strcasecmp -#undef kwsysString_strncasecmp -#endif -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/String.hxx.in b/thirdparty/KWSys/adios2sys/String.hxx.in deleted file mode 100644 index db1cf22a93..0000000000 --- a/thirdparty/KWSys/adios2sys/String.hxx.in +++ /dev/null @@ -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 - -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(l) < - static_cast(r)); -} -#endif - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/System.c b/thirdparty/KWSys/adios2sys/System.c deleted file mode 100644 index b9af8e9d9e..0000000000 --- a/thirdparty/KWSys/adios2sys/System.c +++ /dev/null @@ -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 /* isspace */ -#include /* ptrdiff_t */ -#include /* malloc, free */ -#include /* memcpy */ - -#include - -#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T -typedef ptrdiff_t kwsysSystem_ptrdiff_t; -#else -typedef int kwsysSystem_ptrdiff_t; -#endif - -static int kwsysSystem__AppendByte(char* local, char** begin, char** end, - int* size, char c) -{ - /* Allocate space for the character. */ - if ((*end - *begin) >= *size) { - kwsysSystem_ptrdiff_t length = *end - *begin; - char* newBuffer = (char*)malloc((size_t)(*size * 2)); - if (!newBuffer) { - return 0; - } - memcpy(newBuffer, *begin, (size_t)(length) * sizeof(char)); - if (*begin != local) { - free(*begin); - } - *begin = newBuffer; - *end = *begin + length; - *size *= 2; - } - - /* Store the character. */ - *(*end)++ = c; - return 1; -} - -static int kwsysSystem__AppendArgument(char** local, char*** begin, - char*** end, int* size, char* arg_local, - char** arg_begin, char** arg_end, - int* arg_size) -{ - /* Append a null-terminator to the argument string. */ - if (!kwsysSystem__AppendByte(arg_local, arg_begin, arg_end, arg_size, - '\0')) { - return 0; - } - - /* Allocate space for the argument pointer. */ - if ((*end - *begin) >= *size) { - kwsysSystem_ptrdiff_t length = *end - *begin; - char** newPointers = (char**)malloc((size_t)(*size) * 2 * sizeof(char*)); - if (!newPointers) { - return 0; - } - memcpy(newPointers, *begin, (size_t)(length) * sizeof(char*)); - if (*begin != local) { - free(*begin); - } - *begin = newPointers; - *end = *begin + length; - *size *= 2; - } - - /* Allocate space for the argument string. */ - **end = (char*)malloc((size_t)(*arg_end - *arg_begin)); - if (!**end) { - return 0; - } - - /* Store the argument in the command array. */ - memcpy(**end, *arg_begin, (size_t)(*arg_end - *arg_begin)); - ++(*end); - - /* Reset the argument to be empty. */ - *arg_end = *arg_begin; - - return 1; -} - -#define KWSYSPE_LOCAL_BYTE_COUNT 1024 -#define KWSYSPE_LOCAL_ARGS_COUNT 32 -static char** kwsysSystem__ParseUnixCommand(const char* command, int flags) -{ - /* Create a buffer for argument pointers during parsing. */ - char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT]; - int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT; - char** pointer_begin = local_pointers; - char** pointer_end = pointer_begin; - - /* Create a buffer for argument strings during parsing. */ - char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT]; - int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT; - char* buffer_begin = local_buffer; - char* buffer_end = buffer_begin; - - /* Parse the command string. Try to behave like a UNIX shell. */ - char** newCommand = 0; - const char* c = command; - int in_argument = 0; - int in_escape = 0; - int in_single = 0; - int in_double = 0; - int failed = 0; - for (; *c; ++c) { - if (in_escape) { - /* This character is escaped so do no special handling. */ - if (!in_argument) { - in_argument = 1; - } - if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end, - &buffer_size, *c)) { - failed = 1; - break; - } - in_escape = 0; - } else if (*c == '\\') { - /* The next character should be escaped. */ - in_escape = 1; - } else if (*c == '\'' && !in_double) { - /* Enter or exit single-quote state. */ - if (in_single) { - in_single = 0; - } else { - in_single = 1; - if (!in_argument) { - in_argument = 1; - } - } - } else if (*c == '"' && !in_single) { - /* Enter or exit double-quote state. */ - if (in_double) { - in_double = 0; - } else { - in_double = 1; - if (!in_argument) { - in_argument = 1; - } - } - } else if (isspace((unsigned char)*c)) { - if (in_argument) { - if (in_single || in_double) { - /* This space belongs to a quoted argument. */ - if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, - &buffer_end, &buffer_size, *c)) { - failed = 1; - break; - } - } else { - /* This argument has been terminated by whitespace. */ - if (!kwsysSystem__AppendArgument( - local_pointers, &pointer_begin, &pointer_end, &pointers_size, - local_buffer, &buffer_begin, &buffer_end, &buffer_size)) { - failed = 1; - break; - } - in_argument = 0; - } - } - } else { - /* This character belong to an argument. */ - if (!in_argument) { - in_argument = 1; - } - if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end, - &buffer_size, *c)) { - failed = 1; - break; - } - } - } - - /* Finish the last argument. */ - if (in_argument) { - if (!kwsysSystem__AppendArgument( - local_pointers, &pointer_begin, &pointer_end, &pointers_size, - local_buffer, &buffer_begin, &buffer_end, &buffer_size)) { - failed = 1; - } - } - - /* If we still have memory allocate space for the new command - buffer. */ - if (!failed) { - kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin; - newCommand = (char**)malloc((size_t)(n + 1) * sizeof(char*)); - } - - if (newCommand) { - /* Copy the arguments into the new command buffer. */ - kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin; - memcpy(newCommand, pointer_begin, sizeof(char*) * (size_t)(n)); - newCommand[n] = 0; - } else { - /* Free arguments already allocated. */ - while (pointer_end != pointer_begin) { - free(*(--pointer_end)); - } - } - - /* Free temporary buffers. */ - if (pointer_begin != local_pointers) { - free(pointer_begin); - } - if (buffer_begin != local_buffer) { - free(buffer_begin); - } - - /* The flags argument is currently unused. */ - (void)flags; - - /* Return the final command buffer. */ - return newCommand; -} - -char** kwsysSystem_Parse_CommandForUnix(const char* command, int flags) -{ - /* Validate the flags. */ - if (flags != 0) { - return 0; - } - - /* Forward to our internal implementation. */ - return kwsysSystem__ParseUnixCommand(command, flags); -} diff --git a/thirdparty/KWSys/adios2sys/System.h.in b/thirdparty/KWSys/adios2sys/System.h.in deleted file mode 100644 index 102974db7a..0000000000 --- a/thirdparty/KWSys/adios2sys/System.h.in +++ /dev/null @@ -1,59 +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 diff --git a/thirdparty/KWSys/adios2sys/SystemInformation.cxx b/thirdparty/KWSys/adios2sys/SystemInformation.cxx deleted file mode 100644 index 2b9d7b1741..0000000000 --- a/thirdparty/KWSys/adios2sys/SystemInformation.cxx +++ /dev/null @@ -1,5428 +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 // use our min,max -#if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300) -#define _WIN32_WINNT 0x0501 -#endif -#include // WSADATA, include before sys/types.h -#endif - -#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) -#define _GNU_SOURCE -#endif - -// TODO: -// We need an alternative implementation for many functions in this file -// when USE_ASM_INSTRUCTIONS gets defined as 0. -// -// Consider using these on Win32/Win64 for some of them: -// -// IsProcessorFeaturePresent -// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx -// -// GetProcessMemoryInfo -// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx - -#include "kwsysPrivate.h" -#include KWSYS_HEADER(SystemInformation.hxx) -#include KWSYS_HEADER(Process.h) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -#include "Process.h.in" -#include "SystemInformation.hxx.in" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) -#include -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#define KWSYS_WINDOWS_DEPRECATED_GetVersionEx -#endif -#include -#if defined(KWSYS_SYS_HAS_PSAPI) -#include -#endif -#if !defined(siginfo_t) -typedef int siginfo_t; -#endif -#else -#include - -#include // extern int errno; -#include -#include -#include // getrlimit -#include -#include // int uname(struct utsname *buf); -#include -#endif - -#if defined(__CYGWIN__) && !defined(_WIN32) -#include -#undef _WIN32 -#endif - -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) -#include -#include -#include -#include -#include -#if defined(KWSYS_SYS_HAS_IFADDRS_H) -#include -#include -#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN -#endif -#endif - -#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H) -#include -#endif - -#ifdef __APPLE__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(KWSYS_SYS_HAS_IFADDRS_H) -#include -#include -#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN -#endif -#if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050) -#undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE -#endif -#endif - -#if defined(__linux) || defined(__sun) || defined(_SCO_DS) -#include -#include -#include -#include -#if defined(KWSYS_SYS_HAS_IFADDRS_H) -#include -#include -#if defined(__LSB_VERSION__) -/* LSB has no getifaddrs */ -#elif defined(__ANDROID_API__) && __ANDROID_API__ < 24 -/* Android has no getifaddrs prior to API 24. */ -#else -#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN -#endif -#endif -#if defined(KWSYS_CXX_HAS_RLIMIT64) -typedef struct rlimit64 ResourceLimitType; -#define GetResourceLimit getrlimit64 -#else -typedef struct rlimit ResourceLimitType; -#define GetResourceLimit getrlimit -#endif -#elif defined(__hpux) -#include -#include -#if defined(KWSYS_SYS_HAS_MPCTL_H) -#include -#endif -#endif - -#ifdef __HAIKU__ -#include -#endif - -#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) -#include -#if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) -#include -#endif -#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) -#include -#endif -#else -#undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE -#undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP -#endif - -#include // int isdigit(int c); -#include -#include -#include -#include - -#if defined(KWSYS_USE_LONG_LONG) -#if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) -#define iostreamLongLong(x) (x) -#else -#define iostreamLongLong(x) ((long)(x)) -#endif -#elif defined(KWSYS_USE___INT64) -#if defined(KWSYS_IOS_HAS_OSTREAM___INT64) -#define iostreamLongLong(x) (x) -#else -#define iostreamLongLong(x) ((long)(x)) -#endif -#else -#error "No Long Long" -#endif - -#if defined(KWSYS_CXX_HAS_ATOLL) -#define atoLongLong atoll -#else -#if defined(KWSYS_CXX_HAS__ATOI64) -#define atoLongLong _atoi64 -#elif defined(KWSYS_CXX_HAS_ATOL) -#define atoLongLong atol -#else -#define atoLongLong atoi -#endif -#endif - -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && \ - !defined(__clang__) -#define USE_ASM_INSTRUCTIONS 1 -#else -#define USE_ASM_INSTRUCTIONS 0 -#endif - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__) -#include -#define USE_CPUID_INTRINSICS 1 -#else -#define USE_CPUID_INTRINSICS 0 -#endif - -#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || \ - defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) -#define USE_CPUID 1 -#else -#define USE_CPUID 0 -#endif - -#if USE_CPUID - -#define CPUID_AWARE_COMPILER - -/** - * call CPUID instruction - * - * Will return false if the instruction failed. - */ -static bool call_cpuid(int select, int result[4]) -{ -#if USE_CPUID_INTRINSICS - __cpuid(result, select); - return true; -#else - int tmp[4]; -#if defined(_MSC_VER) - // Use SEH to determine CPUID presence - __try { - _asm { -#ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <> writes to, as the - ; optimiser does not know about <>, and so does not expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -#endif - ; <> - mov eax, select -#ifdef CPUID_AWARE_COMPILER - cpuid -#else - _asm _emit 0x0f - _asm _emit 0xa2 -#endif - mov tmp[0 * TYPE int], eax - mov tmp[1 * TYPE int], ebx - mov tmp[2 * TYPE int], ecx - mov tmp[3 * TYPE int], edx - -#ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -#endif - } - } __except (1) { - return false; - } - - memcpy(result, tmp, sizeof(tmp)); -#elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) - unsigned int a, b, c, d; - __asm { - mov EAX, select; - cpuid - mov a, EAX; - mov b, EBX; - mov c, ECX; - mov d, EDX; - } - - result[0] = a; - result[1] = b; - result[2] = c; - result[3] = d; -#endif - - // The cpuid instruction succeeded. - return true; -#endif -} -#endif - -namespace KWSYS_NAMESPACE { -template -T min(T a, T b) -{ - return a < b ? a : b; -} - -extern "C" { -typedef void (*SigAction)(int, siginfo_t*, void*); -} - -// Define SystemInformationImplementation class -typedef void (*DELAY_FUNC)(unsigned int uiMS); - -class SystemInformationImplementation -{ -public: - typedef SystemInformation::LongLong LongLong; - SystemInformationImplementation(); - ~SystemInformationImplementation(); - - const char* GetVendorString(); - const char* GetVendorID(); - std::string GetTypeID(); - std::string GetFamilyID(); - std::string GetModelID(); - std::string GetModelName(); - std::string GetSteppingCode(); - const char* GetExtendedProcessorName(); - const char* GetProcessorSerialNumber(); - int GetProcessorCacheSize(); - unsigned int GetLogicalProcessorsPerPhysical(); - float GetProcessorClockFrequency(); - int GetProcessorAPICID(); - int GetProcessorCacheXSize(long int); - bool DoesCPUSupportFeature(long int); - - const char* GetOSName(); - const char* GetHostname(); - int GetFullyQualifiedDomainName(std::string& fqdn); - const char* GetOSRelease(); - const char* GetOSVersion(); - const char* GetOSPlatform(); - - bool Is64Bits(); - - unsigned int GetNumberOfLogicalCPU(); // per physical cpu - unsigned int GetNumberOfPhysicalCPU(); - - bool DoesCPUSupportCPUID(); - - // Retrieve memory information in MiB. - size_t GetTotalVirtualMemory(); - size_t GetAvailableVirtualMemory(); - size_t GetTotalPhysicalMemory(); - size_t GetAvailablePhysicalMemory(); - - LongLong GetProcessId(); - - // Retrieve memory information in KiB. - LongLong GetHostMemoryTotal(); - LongLong GetHostMemoryAvailable(const char* envVarName); - LongLong GetHostMemoryUsed(); - - LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName, - const char* procLimitEnvVarName); - LongLong GetProcMemoryUsed(); - - double GetLoadAverage(); - - // enable/disable stack trace signal handler. - static void SetStackTraceOnError(int enable); - - // get current stack - static std::string GetProgramStack(int firstFrame, int wholePath); - - /** Run the different checks */ - void RunCPUCheck(); - void RunOSCheck(); - void RunMemoryCheck(); - -public: - typedef struct tagID - { - int Type; - int Family; - int Model; - int Revision; - int ExtendedFamily; - int ExtendedModel; - std::string ProcessorName; - std::string Vendor; - std::string SerialNumber; - std::string ModelName; - } ID; - - typedef struct tagCPUPowerManagement - { - bool HasVoltageID; - bool HasFrequencyID; - bool HasTempSenseDiode; - } CPUPowerManagement; - - typedef struct tagCPUExtendedFeatures - { - bool Has3DNow; - bool Has3DNowPlus; - bool SupportsMP; - bool HasMMXPlus; - bool HasSSEMMX; - unsigned int LogicalProcessorsPerPhysical; - int APIC_ID; - CPUPowerManagement PowerManagement; - } CPUExtendedFeatures; - - typedef struct CPUtagFeatures - { - bool HasFPU; - bool HasTSC; - bool HasMMX; - bool HasSSE; - bool HasSSEFP; - bool HasSSE2; - bool HasIA64; - bool HasAPIC; - bool HasCMOV; - bool HasMTRR; - bool HasACPI; - bool HasSerial; - bool HasThermal; - int CPUSpeed; - int L1CacheSize; - int L2CacheSize; - int L3CacheSize; - CPUExtendedFeatures ExtendedFeatures; - } CPUFeatures; - - enum Manufacturer - { - AMD, - Intel, - NSC, - UMC, - Cyrix, - NexGen, - IDT, - Rise, - Transmeta, - Sun, - IBM, - Motorola, - HP, - UnknownManufacturer - }; - -protected: - // For windows - bool RetrieveCPUFeatures(); - bool RetrieveCPUIdentity(); - bool RetrieveCPUCacheDetails(); - bool RetrieveClassicalCPUCacheDetails(); - bool RetrieveCPUClockSpeed(); - bool RetrieveClassicalCPUClockSpeed(); - bool RetrieveCPUExtendedLevelSupport(int); - bool RetrieveExtendedCPUFeatures(); - bool RetrieveProcessorSerialNumber(); - bool RetrieveCPUPowerManagement(); - bool RetrieveClassicalCPUIdentity(); - bool RetrieveExtendedCPUIdentity(); - - // Processor information - Manufacturer ChipManufacturer; - CPUFeatures Features; - ID ChipID; - float CPUSpeedInMHz; - unsigned int NumberOfLogicalCPU; - unsigned int NumberOfPhysicalCPU; - - void CPUCountWindows(); // For windows - unsigned char GetAPICId(); // For windows - bool IsSMTSupported(); - static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows - - // For Linux and Cygwin, /proc/cpuinfo formats are slightly different - bool RetreiveInformationFromCpuInfoFile(); - std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word, - size_t init = 0); - - bool QueryLinuxMemory(); - bool QueryCygwinMemory(); - - static void Delay(unsigned int); - static void DelayOverhead(unsigned int); - - void FindManufacturer(const std::string& family = ""); - - // For Mac - bool ParseSysCtl(); - int CallSwVers(const char* arg, std::string& ver); - void TrimNewline(std::string&); - std::string ExtractValueFromSysCtl(const char* word); - std::string SysCtlBuffer; - - // For Solaris - bool QuerySolarisMemory(); - bool QuerySolarisProcessor(); - std::string ParseValueFromKStat(const char* arguments); - std::string RunProcess(std::vector args); - - // For Haiku OS - bool QueryHaikuInfo(); - - // For QNX - bool QueryQNXMemory(); - bool QueryQNXProcessor(); - - // For OpenBSD, FreeBSD, NetBSD, DragonFly - bool QueryBSDMemory(); - bool QueryBSDProcessor(); - - // For HP-UX - bool QueryHPUXMemory(); - bool QueryHPUXProcessor(); - - // For Microsoft Windows - bool QueryWindowsMemory(); - - // For AIX - bool QueryAIXMemory(); - - bool QueryProcessorBySysconf(); - bool QueryProcessor(); - - // Evaluate the memory information. - bool QueryMemoryBySysconf(); - bool QueryMemory(); - size_t TotalVirtualMemory; - size_t AvailableVirtualMemory; - size_t TotalPhysicalMemory; - size_t AvailablePhysicalMemory; - - size_t CurrentPositionInFile; - - // Operating System information - bool QueryOSInformation(); - std::string OSName; - std::string Hostname; - std::string OSRelease; - std::string OSVersion; - std::string OSPlatform; - bool OSIs64Bit; -}; - -SystemInformation::SystemInformation() -{ - this->Implementation = new SystemInformationImplementation; -} - -SystemInformation::~SystemInformation() -{ - delete this->Implementation; -} - -const char* SystemInformation::GetVendorString() -{ - return this->Implementation->GetVendorString(); -} - -const char* SystemInformation::GetVendorID() -{ - return this->Implementation->GetVendorID(); -} - -std::string SystemInformation::GetTypeID() -{ - return this->Implementation->GetTypeID(); -} - -std::string SystemInformation::GetFamilyID() -{ - return this->Implementation->GetFamilyID(); -} - -std::string SystemInformation::GetModelID() -{ - return this->Implementation->GetModelID(); -} - -std::string SystemInformation::GetModelName() -{ - return this->Implementation->GetModelName(); -} - -std::string SystemInformation::GetSteppingCode() -{ - return this->Implementation->GetSteppingCode(); -} - -const char* SystemInformation::GetExtendedProcessorName() -{ - return this->Implementation->GetExtendedProcessorName(); -} - -const char* SystemInformation::GetProcessorSerialNumber() -{ - return this->Implementation->GetProcessorSerialNumber(); -} - -int SystemInformation::GetProcessorCacheSize() -{ - return this->Implementation->GetProcessorCacheSize(); -} - -unsigned int SystemInformation::GetLogicalProcessorsPerPhysical() -{ - return this->Implementation->GetLogicalProcessorsPerPhysical(); -} - -float SystemInformation::GetProcessorClockFrequency() -{ - return this->Implementation->GetProcessorClockFrequency(); -} - -int SystemInformation::GetProcessorAPICID() -{ - return this->Implementation->GetProcessorAPICID(); -} - -int SystemInformation::GetProcessorCacheXSize(long int l) -{ - return this->Implementation->GetProcessorCacheXSize(l); -} - -bool SystemInformation::DoesCPUSupportFeature(long int i) -{ - return this->Implementation->DoesCPUSupportFeature(i); -} - -std::string SystemInformation::GetCPUDescription() -{ - std::ostringstream oss; - oss << this->GetNumberOfPhysicalCPU() << " core "; - if (this->GetModelName().empty()) { - oss << this->GetProcessorClockFrequency() << " MHz " - << this->GetVendorString() << " " << this->GetExtendedProcessorName(); - } else { - oss << this->GetModelName(); - } - - // remove extra spaces - std::string tmp = oss.str(); - size_t pos; - while ((pos = tmp.find(" ")) != std::string::npos) { - tmp.replace(pos, 2, " "); - } - - return tmp; -} - -const char* SystemInformation::GetOSName() -{ - return this->Implementation->GetOSName(); -} - -const char* SystemInformation::GetHostname() -{ - return this->Implementation->GetHostname(); -} - -std::string SystemInformation::GetFullyQualifiedDomainName() -{ - std::string fqdn; - this->Implementation->GetFullyQualifiedDomainName(fqdn); - return fqdn; -} - -const char* SystemInformation::GetOSRelease() -{ - return this->Implementation->GetOSRelease(); -} - -const char* SystemInformation::GetOSVersion() -{ - return this->Implementation->GetOSVersion(); -} - -const char* SystemInformation::GetOSPlatform() -{ - return this->Implementation->GetOSPlatform(); -} - -int SystemInformation::GetOSIsWindows() -{ -#if defined(_WIN32) - return 1; -#else - return 0; -#endif -} - -int SystemInformation::GetOSIsLinux() -{ -#if defined(__linux) - return 1; -#else - return 0; -#endif -} - -int SystemInformation::GetOSIsApple() -{ -#if defined(__APPLE__) - return 1; -#else - return 0; -#endif -} - -std::string SystemInformation::GetOSDescription() -{ - std::ostringstream oss; - oss << this->GetOSName() << " " << this->GetOSRelease() << " " - << this->GetOSVersion(); - - return oss.str(); -} - -bool SystemInformation::Is64Bits() -{ - return this->Implementation->Is64Bits(); -} - -unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu -{ - return this->Implementation->GetNumberOfLogicalCPU(); -} - -unsigned int SystemInformation::GetNumberOfPhysicalCPU() -{ - return this->Implementation->GetNumberOfPhysicalCPU(); -} - -bool SystemInformation::DoesCPUSupportCPUID() -{ - return this->Implementation->DoesCPUSupportCPUID(); -} - -// Retrieve memory information in MiB. -size_t SystemInformation::GetTotalVirtualMemory() -{ - return this->Implementation->GetTotalVirtualMemory(); -} - -size_t SystemInformation::GetAvailableVirtualMemory() -{ - return this->Implementation->GetAvailableVirtualMemory(); -} - -size_t SystemInformation::GetTotalPhysicalMemory() -{ - return this->Implementation->GetTotalPhysicalMemory(); -} - -size_t SystemInformation::GetAvailablePhysicalMemory() -{ - return this->Implementation->GetAvailablePhysicalMemory(); -} - -std::string SystemInformation::GetMemoryDescription( - const char* hostLimitEnvVarName, const char* procLimitEnvVarName) -{ - std::ostringstream oss; - oss << "Host Total: " << iostreamLongLong(this->GetHostMemoryTotal()) - << " KiB, Host Available: " - << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName)) - << " KiB, Process Available: " - << iostreamLongLong(this->GetProcMemoryAvailable(hostLimitEnvVarName, - procLimitEnvVarName)) - << " KiB"; - return oss.str(); -} - -// host memory info in units of KiB. -SystemInformation::LongLong SystemInformation::GetHostMemoryTotal() -{ - return this->Implementation->GetHostMemoryTotal(); -} - -SystemInformation::LongLong SystemInformation::GetHostMemoryAvailable( - const char* hostLimitEnvVarName) -{ - return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName); -} - -SystemInformation::LongLong SystemInformation::GetHostMemoryUsed() -{ - return this->Implementation->GetHostMemoryUsed(); -} - -// process memory info in units of KiB. -SystemInformation::LongLong SystemInformation::GetProcMemoryAvailable( - const char* hostLimitEnvVarName, const char* procLimitEnvVarName) -{ - return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName, - procLimitEnvVarName); -} - -SystemInformation::LongLong SystemInformation::GetProcMemoryUsed() -{ - return this->Implementation->GetProcMemoryUsed(); -} - -double SystemInformation::GetLoadAverage() -{ - return this->Implementation->GetLoadAverage(); -} - -SystemInformation::LongLong SystemInformation::GetProcessId() -{ - return this->Implementation->GetProcessId(); -} - -void SystemInformation::SetStackTraceOnError(int enable) -{ - SystemInformationImplementation::SetStackTraceOnError(enable); -} - -std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath) -{ - return SystemInformationImplementation::GetProgramStack(firstFrame, - wholePath); -} - -/** Run the different checks */ -void SystemInformation::RunCPUCheck() -{ - this->Implementation->RunCPUCheck(); -} - -void SystemInformation::RunOSCheck() -{ - this->Implementation->RunOSCheck(); -} - -void SystemInformation::RunMemoryCheck() -{ - this->Implementation->RunMemoryCheck(); -} - -// SystemInformationImplementation starts here - -#define STORE_TLBCACHE_INFO(x, y) x = (x < (y)) ? (y) : x -#define TLBCACHE_INFO_UNITS (15) -#define CLASSICAL_CPU_FREQ_LOOP 10000000 -#define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31 - -// Status Flag -#define HT_NOT_CAPABLE 0 -#define HT_ENABLED 1 -#define HT_DISABLED 2 -#define HT_SUPPORTED_NOT_ENABLED 3 -#define HT_CANNOT_DETECT 4 - -// EDX[28] Bit 28 is set if HT is supported -#define HT_BIT 0x10000000 - -// EAX[11:8] Bit 8-11 contains family processor ID. -#define FAMILY_ID 0x0F00 -#define PENTIUM4_ID 0x0F00 -// EAX[23:20] Bit 20-23 contains extended family processor ID -#define EXT_FAMILY_ID 0x0F00000 -// EBX[23:16] Bit 16-23 in ebx contains the number of logical -#define NUM_LOGICAL_BITS 0x00FF0000 -// processors per physical processor when execute cpuid with -// eax set to 1 -// EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique -#define INITIAL_APIC_ID_BITS 0xFF000000 -// initial APIC ID for the processor this code is running on. -// Default value = 0xff if HT is not supported - -// Hide implementation details in an anonymous namespace. -namespace { -// ***************************************************************************** -#if defined(__linux) || defined(__APPLE__) -int LoadLines(FILE* file, std::vector& lines) -{ - // Load each line in the given file into a the vector. - int nRead = 0; - const int bufSize = 1024; - char buf[bufSize] = { '\0' }; - while (!feof(file) && !ferror(file)) { - errno = 0; - if (fgets(buf, bufSize, file) == KWSYS_NULLPTR) { - if (ferror(file) && (errno == EINTR)) { - clearerr(file); - } - continue; - } - char* pBuf = buf; - while (*pBuf) { - if (*pBuf == '\n') - *pBuf = '\0'; - pBuf += 1; - } - lines.push_back(buf); - ++nRead; - } - if (ferror(file)) { - return 0; - } - return nRead; -} - -#if defined(__linux) -// ***************************************************************************** -int LoadLines(const char* fileName, std::vector& lines) -{ - FILE* file = fopen(fileName, "r"); - if (file == 0) { - return 0; - } - int nRead = LoadLines(file, lines); - fclose(file); - return nRead; -} -#endif - -// **************************************************************************** -template -int NameValue(std::vector const& lines, std::string const& name, - T& value) -{ - size_t nLines = lines.size(); - for (size_t i = 0; i < nLines; ++i) { - size_t at = lines[i].find(name); - if (at == std::string::npos) { - continue; - } - std::istringstream is(lines[i].substr(at + name.size())); - is >> value; - return 0; - } - return -1; -} -#endif - -#if defined(__linux) -// **************************************************************************** -template -int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values) -{ - std::vector fields; - if (!LoadLines(fileName, fields)) { - return -1; - } - int i = 0; - while (fieldNames[i] != NULL) { - int ierr = NameValue(fields, fieldNames[i], values[i]); - if (ierr) { - return -(i + 2); - } - i += 1; - } - return 0; -} - -// **************************************************************************** -template -int GetFieldFromFile(const char* fileName, const char* fieldName, T& value) -{ - const char* fieldNames[2] = { fieldName, NULL }; - T values[1] = { T(0) }; - int ierr = GetFieldsFromFile(fileName, fieldNames, values); - if (ierr) { - return ierr; - } - value = values[0]; - return 0; -} -#endif - -// **************************************************************************** -#if defined(__APPLE__) -template -int GetFieldsFromCommand(const char* command, const char** fieldNames, - T* values) -{ - FILE* file = popen(command, "r"); - if (file == KWSYS_NULLPTR) { - return -1; - } - std::vector fields; - int nl = LoadLines(file, fields); - pclose(file); - if (nl == 0) { - return -1; - } - int i = 0; - while (fieldNames[i] != KWSYS_NULLPTR) { - int ierr = NameValue(fields, fieldNames[i], values[i]); - if (ierr) { - return -(i + 2); - } - i += 1; - } - return 0; -} -#endif - -// **************************************************************************** -#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) -void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo, - void* /*sigContext*/) -{ -#if defined(__linux) || defined(__APPLE__) - std::ostringstream oss; - oss << std::endl - << "=========================================================" - << std::endl - << "Process id " << getpid() << " "; - switch (sigNo) { - case SIGINT: - oss << "Caught SIGINT"; - break; - - case SIGTERM: - oss << "Caught SIGTERM"; - break; - - case SIGABRT: - oss << "Caught SIGABRT"; - break; - - case SIGFPE: - oss << "Caught SIGFPE at " - << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "") - << sigInfo->si_addr << " "; - switch (sigInfo->si_code) { -#if defined(FPE_INTDIV) - case FPE_INTDIV: - oss << "integer division by zero"; - break; -#endif - -#if defined(FPE_INTOVF) - case FPE_INTOVF: - oss << "integer overflow"; - break; -#endif - - case FPE_FLTDIV: - oss << "floating point divide by zero"; - break; - - case FPE_FLTOVF: - oss << "floating point overflow"; - break; - - case FPE_FLTUND: - oss << "floating point underflow"; - break; - - case FPE_FLTRES: - oss << "floating point inexact result"; - break; - - case FPE_FLTINV: - oss << "floating point invalid operation"; - break; - -#if defined(FPE_FLTSUB) - case FPE_FLTSUB: - oss << "floating point subscript out of range"; - break; -#endif - - default: - oss << "code " << sigInfo->si_code; - break; - } - break; - - case SIGSEGV: - oss << "Caught SIGSEGV at " - << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "") - << sigInfo->si_addr << " "; - switch (sigInfo->si_code) { - case SEGV_MAPERR: - oss << "address not mapped to object"; - break; - - case SEGV_ACCERR: - oss << "invalid permission for mapped object"; - break; - - default: - oss << "code " << sigInfo->si_code; - break; - } - break; - - case SIGBUS: - oss << "Caught SIGBUS at " - << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "") - << sigInfo->si_addr << " "; - switch (sigInfo->si_code) { - case BUS_ADRALN: - oss << "invalid address alignment"; - break; - -#if defined(BUS_ADRERR) - case BUS_ADRERR: - oss << "nonexistent physical address"; - break; -#endif - -#if defined(BUS_OBJERR) - case BUS_OBJERR: - oss << "object-specific hardware error"; - break; -#endif - -#if defined(BUS_MCEERR_AR) - case BUS_MCEERR_AR: - oss << "Hardware memory error consumed on a machine check; action " - "required."; - break; -#endif - -#if defined(BUS_MCEERR_AO) - case BUS_MCEERR_AO: - oss << "Hardware memory error detected in process but not consumed; " - "action optional."; - break; -#endif - - default: - oss << "code " << sigInfo->si_code; - break; - } - break; - - case SIGILL: - oss << "Caught SIGILL at " - << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "") - << sigInfo->si_addr << " "; - switch (sigInfo->si_code) { - case ILL_ILLOPC: - oss << "illegal opcode"; - break; - -#if defined(ILL_ILLOPN) - case ILL_ILLOPN: - oss << "illegal operand"; - break; -#endif - -#if defined(ILL_ILLADR) - case ILL_ILLADR: - oss << "illegal addressing mode."; - break; -#endif - - case ILL_ILLTRP: - oss << "illegal trap"; - break; - - case ILL_PRVOPC: - oss << "privileged opcode"; - break; - -#if defined(ILL_PRVREG) - case ILL_PRVREG: - oss << "privileged register"; - break; -#endif - -#if defined(ILL_COPROC) - case ILL_COPROC: - oss << "co-processor error"; - break; -#endif - -#if defined(ILL_BADSTK) - case ILL_BADSTK: - oss << "internal stack error"; - break; -#endif - - default: - oss << "code " << sigInfo->si_code; - break; - } - break; - - default: - oss << "Caught " << sigNo << " code " << sigInfo->si_code; - break; - } - oss << std::endl - << "Program Stack:" << std::endl - << SystemInformationImplementation::GetProgramStack(2, 0) - << "=========================================================" - << std::endl; - std::cerr << oss.str() << std::endl; - - // restore the previously registered handlers - // and abort - SystemInformationImplementation::SetStackTraceOnError(0); - abort(); -#else - // avoid warning C4100 - (void)sigNo; - (void)sigInfo; -#endif -} -#endif - -#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) -#define safes(_arg) ((_arg) ? (_arg) : "???") - -// Description: -// A container for symbol properties. Each instance -// must be Initialized. -class SymbolProperties -{ -public: - SymbolProperties(); - - // Description: - // The SymbolProperties instance must be initialized by - // passing a stack address. - void Initialize(void* address); - - // Description: - // Get the symbol's stack address. - void* GetAddress() const { return this->Address; } - - // Description: - // If not set paths will be removed. eg, from a binary - // or source file. - void SetReportPath(int rp) { this->ReportPath = rp; } - - // Description: - // Set/Get the name of the binary file that the symbol - // is found in. - void SetBinary(const char* binary) { this->Binary = safes(binary); } - - std::string GetBinary() const; - - // Description: - // Set the name of the function that the symbol is found in. - // If c++ demangling is supported it will be demangled. - void SetFunction(const char* function) - { - this->Function = this->Demangle(function); - } - - std::string GetFunction() const { return this->Function; } - - // Description: - // Set/Get the name of the source file where the symbol - // is defined. - void SetSourceFile(const char* sourcefile) - { - this->SourceFile = safes(sourcefile); - } - - std::string GetSourceFile() const - { - return this->GetFileName(this->SourceFile); - } - - // Description: - // Set/Get the line number where the symbol is defined - void SetLineNumber(long linenumber) { this->LineNumber = linenumber; } - long GetLineNumber() const { return this->LineNumber; } - - // Description: - // Set the address where the biinary image is mapped - // into memory. - void SetBinaryBaseAddress(void* address) - { - this->BinaryBaseAddress = address; - } - -private: - void* GetRealAddress() const - { - return (void*)((char*)this->Address - (char*)this->BinaryBaseAddress); - } - - std::string GetFileName(const std::string& path) const; - std::string Demangle(const char* symbol) const; - -private: - std::string Binary; - void* BinaryBaseAddress; - void* Address; - std::string SourceFile; - std::string Function; - long LineNumber; - int ReportPath; -}; - -std::ostream& operator<<(std::ostream& os, const SymbolProperties& sp) -{ -#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) - os << std::hex << sp.GetAddress() << " : " << sp.GetFunction() << " [(" - << sp.GetBinary() << ") " << sp.GetSourceFile() << ":" << std::dec - << sp.GetLineNumber() << "]"; -#elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) - void* addr = sp.GetAddress(); - char** syminfo = backtrace_symbols(&addr, 1); - os << safes(syminfo[0]); - free(syminfo); -#else - (void)os; - (void)sp; -#endif - return os; -} - -SymbolProperties::SymbolProperties() -{ - // not using an initializer list - // to avoid some PGI compiler warnings - this->SetBinary("???"); - this->SetBinaryBaseAddress(KWSYS_NULLPTR); - this->Address = KWSYS_NULLPTR; - this->SetSourceFile("???"); - this->SetFunction("???"); - this->SetLineNumber(-1); - this->SetReportPath(0); - // avoid PGI compiler warnings - this->GetRealAddress(); - this->GetFunction(); - this->GetSourceFile(); - this->GetLineNumber(); -} - -std::string SymbolProperties::GetFileName(const std::string& path) const -{ - std::string file(path); - if (!this->ReportPath) { - size_t at = file.rfind("/"); - if (at != std::string::npos) { - file = file.substr(at + 1); - } - } - return file; -} - -std::string SymbolProperties::GetBinary() const -{ -// only linux has proc fs -#if defined(__linux__) - if (this->Binary == "/proc/self/exe") { - std::string binary; - char buf[1024] = { '\0' }; - ssize_t ll = 0; - if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0 && ll < 1024) { - buf[ll] = '\0'; - binary = buf; - } else { - binary = "/proc/self/exe"; - } - return this->GetFileName(binary); - } -#endif - return this->GetFileName(this->Binary); -} - -std::string SymbolProperties::Demangle(const char* symbol) const -{ - std::string result = safes(symbol); -#if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) - int status = 0; - size_t bufferLen = 1024; - char* buffer = (char*)malloc(1024); - char* demangledSymbol = - abi::__cxa_demangle(symbol, buffer, &bufferLen, &status); - if (!status) { - result = demangledSymbol; - } - free(buffer); -#else - (void)symbol; -#endif - return result; -} - -void SymbolProperties::Initialize(void* address) -{ - this->Address = address; -#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) - // first fallback option can demangle c++ functions - Dl_info info; - int ierr = dladdr(this->Address, &info); - if (ierr && info.dli_sname && info.dli_saddr) { - this->SetBinary(info.dli_fname); - this->SetFunction(info.dli_sname); - } -#else -// second fallback use builtin backtrace_symbols -// to decode the bactrace. -#endif -} -#endif // don't define this class if we're not using it - -#if defined(_WIN32) || defined(__CYGWIN__) -#define KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes -#endif -#if defined(_MSC_VER) && _MSC_VER < 1310 -#undef KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes -#endif -#if defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes) -double calculateCPULoad(unsigned __int64 idleTicks, - unsigned __int64 totalTicks) -{ - static double previousLoad = -0.0; - static unsigned __int64 previousIdleTicks = 0; - static unsigned __int64 previousTotalTicks = 0; - - unsigned __int64 const idleTicksSinceLastTime = - idleTicks - previousIdleTicks; - unsigned __int64 const totalTicksSinceLastTime = - totalTicks - previousTotalTicks; - - double load; - if (previousTotalTicks == 0 || totalTicksSinceLastTime == 0) { - // No new information. Use previous result. - load = previousLoad; - } else { - // Calculate load since last time. - load = 1.0 - double(idleTicksSinceLastTime) / totalTicksSinceLastTime; - - // Smooth if possible. - if (previousLoad > 0) { - load = 0.25 * load + 0.75 * previousLoad; - } - } - - previousLoad = load; - previousIdleTicks = idleTicks; - previousTotalTicks = totalTicks; - - return load; -} - -unsigned __int64 fileTimeToUInt64(FILETIME const& ft) -{ - LARGE_INTEGER out; - out.HighPart = ft.dwHighDateTime; - out.LowPart = ft.dwLowDateTime; - return out.QuadPart; -} -#endif - -} // anonymous namespace - -SystemInformationImplementation::SystemInformationImplementation() -{ - this->TotalVirtualMemory = 0; - this->AvailableVirtualMemory = 0; - this->TotalPhysicalMemory = 0; - this->AvailablePhysicalMemory = 0; - this->CurrentPositionInFile = 0; - this->ChipManufacturer = UnknownManufacturer; - memset(&this->Features, 0, sizeof(CPUFeatures)); - this->ChipID.Type = 0; - this->ChipID.Family = 0; - this->ChipID.Model = 0; - this->ChipID.Revision = 0; - this->ChipID.ExtendedFamily = 0; - this->ChipID.ExtendedModel = 0; - this->CPUSpeedInMHz = 0; - this->NumberOfLogicalCPU = 0; - this->NumberOfPhysicalCPU = 0; - this->OSName = ""; - this->Hostname = ""; - this->OSRelease = ""; - this->OSVersion = ""; - this->OSPlatform = ""; - this->OSIs64Bit = (sizeof(void*) == 8); -} - -SystemInformationImplementation::~SystemInformationImplementation() -{ -} - -void SystemInformationImplementation::RunCPUCheck() -{ -#ifdef _WIN32 - // Check to see if this processor supports CPUID. - bool supportsCPUID = DoesCPUSupportCPUID(); - - if (supportsCPUID) { - // Retrieve the CPU details. - RetrieveCPUIdentity(); - this->FindManufacturer(); - RetrieveCPUFeatures(); - } - - // These two may be called without support for the CPUID instruction. - // (But if the instruction is there, they should be called *after* - // the above call to RetrieveCPUIdentity... that's why the two if - // blocks exist with the same "if (supportsCPUID)" logic... - // - if (!RetrieveCPUClockSpeed()) { - RetrieveClassicalCPUClockSpeed(); - } - - if (supportsCPUID) { - // Retrieve cache information. - if (!RetrieveCPUCacheDetails()) { - RetrieveClassicalCPUCacheDetails(); - } - - // Retrieve the extended CPU details. - if (!RetrieveExtendedCPUIdentity()) { - RetrieveClassicalCPUIdentity(); - } - - RetrieveExtendedCPUFeatures(); - RetrieveCPUPowerManagement(); - - // Now attempt to retrieve the serial number (if possible). - RetrieveProcessorSerialNumber(); - } - - this->CPUCountWindows(); - -#elif defined(__APPLE__) - this->ParseSysCtl(); -#elif defined(__SVR4) && defined(__sun) - this->QuerySolarisProcessor(); -#elif defined(__HAIKU__) - this->QueryHaikuInfo(); -#elif defined(__QNX__) - this->QueryQNXProcessor(); -#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) - this->QueryBSDProcessor(); -#elif defined(__hpux) - this->QueryHPUXProcessor(); -#elif defined(__linux) || defined(__CYGWIN__) - this->RetreiveInformationFromCpuInfoFile(); -#else - this->QueryProcessor(); -#endif -} - -void SystemInformationImplementation::RunOSCheck() -{ - this->QueryOSInformation(); -} - -void SystemInformationImplementation::RunMemoryCheck() -{ -#if defined(__APPLE__) - this->ParseSysCtl(); -#elif defined(__SVR4) && defined(__sun) - this->QuerySolarisMemory(); -#elif defined(__HAIKU__) - this->QueryHaikuInfo(); -#elif defined(__QNX__) - this->QueryQNXMemory(); -#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) - this->QueryBSDMemory(); -#elif defined(__CYGWIN__) - this->QueryCygwinMemory(); -#elif defined(_WIN32) - this->QueryWindowsMemory(); -#elif defined(__hpux) - this->QueryHPUXMemory(); -#elif defined(__linux) - this->QueryLinuxMemory(); -#elif defined(_AIX) - this->QueryAIXMemory(); -#else - this->QueryMemory(); -#endif -} - -/** Get the vendor string */ -const char* SystemInformationImplementation::GetVendorString() -{ - return this->ChipID.Vendor.c_str(); -} - -/** Get the OS Name */ -const char* SystemInformationImplementation::GetOSName() -{ - return this->OSName.c_str(); -} - -/** Get the hostname */ -const char* SystemInformationImplementation::GetHostname() -{ - if (this->Hostname.empty()) { - this->Hostname = "localhost"; -#if defined(_WIN32) - WORD wVersionRequested; - WSADATA wsaData; - char name[255]; - wVersionRequested = MAKEWORD(2, 0); - if (WSAStartup(wVersionRequested, &wsaData) == 0) { - gethostname(name, sizeof(name)); - WSACleanup(); - } - this->Hostname = name; -#else - struct utsname unameInfo; - int errorFlag = uname(&unameInfo); - if (errorFlag == 0) { - this->Hostname = unameInfo.nodename; - } -#endif - } - return this->Hostname.c_str(); -} - -/** Get the FQDN */ -int SystemInformationImplementation::GetFullyQualifiedDomainName( - std::string& fqdn) -{ - // in the event of absolute failure return localhost. - fqdn = "localhost"; - -#if defined(_WIN32) - int ierr; - // TODO - a more robust implementation for windows, see comments - // in unix implementation. - WSADATA wsaData; - WORD ver = MAKEWORD(2, 0); - ierr = WSAStartup(ver, &wsaData); - if (ierr) { - return -1; - } - - char base[256] = { '\0' }; - ierr = gethostname(base, 256); - if (ierr) { - WSACleanup(); - return -2; - } - fqdn = base; - - HOSTENT* hent = gethostbyname(base); - if (hent) { - fqdn = hent->h_name; - } - - WSACleanup(); - return 0; - -#elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN) - // gethostname typical returns an alias for loopback interface - // we want the fully qualified domain name. Because there are - // any number of interfaces on this system we look for the - // first of these that contains the name returned by gethostname - // and is longer. failing that we return gethostname and indicate - // with a failure code. Return of a failure code is not necessarily - // an indication of an error. for instance gethostname may return - // the fully qualified domain name, or there may not be one if the - // system lives on a private network such as in the case of a cluster - // node. - - int ierr = 0; - char base[NI_MAXHOST]; - ierr = gethostname(base, NI_MAXHOST); - if (ierr) { - return -1; - } - size_t baseSize = strlen(base); - fqdn = base; - - struct ifaddrs* ifas; - struct ifaddrs* ifa; - ierr = getifaddrs(&ifas); - if (ierr) { - return -2; - } - - for (ifa = ifas; ifa != KWSYS_NULLPTR; ifa = ifa->ifa_next) { - int fam = ifa->ifa_addr ? ifa->ifa_addr->sa_family : -1; - // Skip Loopback interfaces - if (((fam == AF_INET) || (fam == AF_INET6)) && - !(ifa->ifa_flags & IFF_LOOPBACK)) { - char host[NI_MAXHOST] = { '\0' }; - - const size_t addrlen = (fam == AF_INET ? sizeof(struct sockaddr_in) - : sizeof(struct sockaddr_in6)); - - ierr = getnameinfo(ifa->ifa_addr, static_cast(addrlen), host, - NI_MAXHOST, KWSYS_NULLPTR, 0, NI_NAMEREQD); - if (ierr) { - // don't report the failure now since we may succeed on another - // interface. If all attempts fail then return the failure code. - ierr = -3; - continue; - } - - std::string candidate = host; - if ((candidate.find(base) != std::string::npos) && - baseSize < candidate.size()) { - // success, stop now. - ierr = 0; - fqdn = candidate; - break; - } - } - } - freeifaddrs(ifas); - - return ierr; -#else - /* TODO: Implement on more platforms. */ - fqdn = this->GetHostname(); - return -1; -#endif -} - -/** Get the OS release */ -const char* SystemInformationImplementation::GetOSRelease() -{ - return this->OSRelease.c_str(); -} - -/** Get the OS version */ -const char* SystemInformationImplementation::GetOSVersion() -{ - return this->OSVersion.c_str(); -} - -/** Get the OS platform */ -const char* SystemInformationImplementation::GetOSPlatform() -{ - return this->OSPlatform.c_str(); -} - -/** Get the vendor ID */ -const char* SystemInformationImplementation::GetVendorID() -{ - // Return the vendor ID. - switch (this->ChipManufacturer) { - case Intel: - return "Intel Corporation"; - case AMD: - return "Advanced Micro Devices"; - case NSC: - return "National Semiconductor"; - case Cyrix: - return "Cyrix Corp., VIA Inc."; - case NexGen: - return "NexGen Inc., Advanced Micro Devices"; - case IDT: - return "IDT\\Centaur, Via Inc."; - case UMC: - return "United Microelectronics Corp."; - case Rise: - return "Rise"; - case Transmeta: - return "Transmeta"; - case Sun: - return "Sun Microelectronics"; - case IBM: - return "IBM"; - case Motorola: - return "Motorola"; - case HP: - return "Hewlett-Packard"; - case UnknownManufacturer: - default: - return "Unknown Manufacturer"; - } -} - -/** Return the type ID of the CPU */ -std::string SystemInformationImplementation::GetTypeID() -{ - std::ostringstream str; - str << this->ChipID.Type; - return str.str(); -} - -/** Return the family of the CPU present */ -std::string SystemInformationImplementation::GetFamilyID() -{ - std::ostringstream str; - str << this->ChipID.Family; - return str.str(); -} - -// Return the model of CPU present */ -std::string SystemInformationImplementation::GetModelID() -{ - std::ostringstream str; - str << this->ChipID.Model; - return str.str(); -} - -// Return the model name of CPU present */ -std::string SystemInformationImplementation::GetModelName() -{ - return this->ChipID.ModelName; -} - -/** Return the stepping code of the CPU present. */ -std::string SystemInformationImplementation::GetSteppingCode() -{ - std::ostringstream str; - str << this->ChipID.Revision; - return str.str(); -} - -/** Return the stepping code of the CPU present. */ -const char* SystemInformationImplementation::GetExtendedProcessorName() -{ - return this->ChipID.ProcessorName.c_str(); -} - -/** Return the serial number of the processor - * in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */ -const char* SystemInformationImplementation::GetProcessorSerialNumber() -{ - return this->ChipID.SerialNumber.c_str(); -} - -/** Return the logical processors per physical */ -unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical() -{ - return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical; -} - -/** Return the processor clock frequency. */ -float SystemInformationImplementation::GetProcessorClockFrequency() -{ - return this->CPUSpeedInMHz; -} - -/** Return the APIC ID. */ -int SystemInformationImplementation::GetProcessorAPICID() -{ - return this->Features.ExtendedFeatures.APIC_ID; -} - -/** Return the L1 cache size. */ -int SystemInformationImplementation::GetProcessorCacheSize() -{ - return this->Features.L1CacheSize; -} - -/** Return the chosen cache size. */ -int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID) -{ - switch (dwCacheID) { - case SystemInformation::CPU_FEATURE_L1CACHE: - return this->Features.L1CacheSize; - case SystemInformation::CPU_FEATURE_L2CACHE: - return this->Features.L2CacheSize; - case SystemInformation::CPU_FEATURE_L3CACHE: - return this->Features.L3CacheSize; - } - return -1; -} - -bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature) -{ - bool bHasFeature = false; - - // Check for MMX instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_MMX) != 0) && - this->Features.HasMMX) - bHasFeature = true; - - // Check for MMX+ instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_MMX_PLUS) != 0) && - this->Features.ExtendedFeatures.HasMMXPlus) - bHasFeature = true; - - // Check for SSE FP instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_SSE) != 0) && - this->Features.HasSSE) - bHasFeature = true; - - // Check for SSE FP instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_FP) != 0) && - this->Features.HasSSEFP) - bHasFeature = true; - - // Check for SSE MMX instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_MMX) != 0) && - this->Features.ExtendedFeatures.HasSSEMMX) - bHasFeature = true; - - // Check for SSE2 instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_SSE2) != 0) && - this->Features.HasSSE2) - bHasFeature = true; - - // Check for 3DNow! instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW) != 0) && - this->Features.ExtendedFeatures.Has3DNow) - bHasFeature = true; - - // Check for 3DNow+ instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW_PLUS) != 0) && - this->Features.ExtendedFeatures.Has3DNowPlus) - bHasFeature = true; - - // Check for IA64 instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_IA64) != 0) && - this->Features.HasIA64) - bHasFeature = true; - - // Check for MP capable. - if (((dwFeature & SystemInformation::CPU_FEATURE_MP_CAPABLE) != 0) && - this->Features.ExtendedFeatures.SupportsMP) - bHasFeature = true; - - // Check for a serial number for the processor. - if (((dwFeature & SystemInformation::CPU_FEATURE_SERIALNUMBER) != 0) && - this->Features.HasSerial) - bHasFeature = true; - - // Check for a local APIC in the processor. - if (((dwFeature & SystemInformation::CPU_FEATURE_APIC) != 0) && - this->Features.HasAPIC) - bHasFeature = true; - - // Check for CMOV instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_CMOV) != 0) && - this->Features.HasCMOV) - bHasFeature = true; - - // Check for MTRR instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_MTRR) != 0) && - this->Features.HasMTRR) - bHasFeature = true; - - // Check for L1 cache size. - if (((dwFeature & SystemInformation::CPU_FEATURE_L1CACHE) != 0) && - (this->Features.L1CacheSize != -1)) - bHasFeature = true; - - // Check for L2 cache size. - if (((dwFeature & SystemInformation::CPU_FEATURE_L2CACHE) != 0) && - (this->Features.L2CacheSize != -1)) - bHasFeature = true; - - // Check for L3 cache size. - if (((dwFeature & SystemInformation::CPU_FEATURE_L3CACHE) != 0) && - (this->Features.L3CacheSize != -1)) - bHasFeature = true; - - // Check for ACPI capability. - if (((dwFeature & SystemInformation::CPU_FEATURE_ACPI) != 0) && - this->Features.HasACPI) - bHasFeature = true; - - // Check for thermal monitor support. - if (((dwFeature & SystemInformation::CPU_FEATURE_THERMALMONITOR) != 0) && - this->Features.HasThermal) - bHasFeature = true; - - // Check for temperature sensing diode support. - if (((dwFeature & SystemInformation::CPU_FEATURE_TEMPSENSEDIODE) != 0) && - this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) - bHasFeature = true; - - // Check for frequency ID support. - if (((dwFeature & SystemInformation::CPU_FEATURE_FREQUENCYID) != 0) && - this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID) - bHasFeature = true; - - // Check for voltage ID support. - if (((dwFeature & SystemInformation::CPU_FEATURE_VOLTAGEID_FREQUENCY) != - 0) && - this->Features.ExtendedFeatures.PowerManagement.HasVoltageID) - bHasFeature = true; - - // Check for FPU support. - if (((dwFeature & SystemInformation::CPU_FEATURE_FPU) != 0) && - this->Features.HasFPU) - bHasFeature = true; - - return bHasFeature; -} - -void SystemInformationImplementation::Delay(unsigned int uiMS) -{ -#ifdef _WIN32 - LARGE_INTEGER Frequency, StartCounter, EndCounter; - __int64 x; - - // Get the frequency of the high performance counter. - if (!QueryPerformanceFrequency(&Frequency)) - return; - x = Frequency.QuadPart / 1000 * uiMS; - - // Get the starting position of the counter. - QueryPerformanceCounter(&StartCounter); - - do { - // Get the ending position of the counter. - QueryPerformanceCounter(&EndCounter); - } while (EndCounter.QuadPart - StartCounter.QuadPart < x); -#endif - (void)uiMS; -} - -bool SystemInformationImplementation::DoesCPUSupportCPUID() -{ -#if USE_CPUID - int dummy[4] = { 0, 0, 0, 0 }; - -#if USE_ASM_INSTRUCTIONS - return call_cpuid(0, dummy); -#else - call_cpuid(0, dummy); - return dummy[0] || dummy[1] || dummy[2] || dummy[3]; -#endif -#else - // Assume no cpuid instruction. - return false; -#endif -} - -bool SystemInformationImplementation::RetrieveCPUFeatures() -{ -#if USE_CPUID - int cpuinfo[4] = { 0, 0, 0, 0 }; - - if (!call_cpuid(1, cpuinfo)) { - return false; - } - - // Retrieve the features of CPU present. - this->Features.HasFPU = - ((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0 - this->Features.HasTSC = - ((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4 - this->Features.HasAPIC = - ((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9 - this->Features.HasMTRR = - ((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12 - this->Features.HasCMOV = - ((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15 - this->Features.HasSerial = - ((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18 - this->Features.HasACPI = - ((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22 - this->Features.HasMMX = - ((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23 - this->Features.HasSSE = - ((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25 - this->Features.HasSSE2 = - ((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26 - this->Features.HasThermal = - ((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29 - this->Features.HasIA64 = - ((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30 - -#if USE_ASM_INSTRUCTIONS - // Retrieve extended SSE capabilities if SSE is available. - if (this->Features.HasSSE) { - - // Attempt to __try some SSE FP instructions. - __try { - // Perform: orps xmm0, xmm0 - _asm - { - _emit 0x0f - _emit 0x56 - _emit 0xc0 - } - - // SSE FP capable processor. - this->Features.HasSSEFP = true; - } __except (1) { - // bad instruction - processor or OS cannot handle SSE FP. - this->Features.HasSSEFP = false; - } - } else { - // Set the advanced SSE capabilities to not available. - this->Features.HasSSEFP = false; - } -#else - this->Features.HasSSEFP = false; -#endif - - // Retrieve Intel specific extended features. - if (this->ChipManufacturer == Intel) { - bool SupportsSMT = - ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: SMT --> Bit 28 - - if ((SupportsSMT) && (this->Features.HasAPIC)) { - // Retrieve APIC information if there is one present. - this->Features.ExtendedFeatures.APIC_ID = - ((cpuinfo[1] & 0xFF000000) >> 24); - } - } - - return true; - -#else - return false; -#endif -} - -/** Find the manufacturer given the vendor id */ -void SystemInformationImplementation::FindManufacturer( - const std::string& family) -{ - if (this->ChipID.Vendor == "GenuineIntel") - this->ChipManufacturer = Intel; // Intel Corp. - else if (this->ChipID.Vendor == "UMC UMC UMC ") - this->ChipManufacturer = UMC; // United Microelectronics Corp. - else if (this->ChipID.Vendor == "AuthenticAMD") - this->ChipManufacturer = AMD; // Advanced Micro Devices - else if (this->ChipID.Vendor == "AMD ISBETTER") - this->ChipManufacturer = AMD; // Advanced Micro Devices (1994) - else if (this->ChipID.Vendor == "CyrixInstead") - this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc. - else if (this->ChipID.Vendor == "NexGenDriven") - this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD) - else if (this->ChipID.Vendor == "CentaurHauls") - this->ChipManufacturer = IDT; // IDT/Centaur (now VIA) - else if (this->ChipID.Vendor == "RiseRiseRise") - this->ChipManufacturer = Rise; // Rise - else if (this->ChipID.Vendor == "GenuineTMx86") - this->ChipManufacturer = Transmeta; // Transmeta - else if (this->ChipID.Vendor == "TransmetaCPU") - this->ChipManufacturer = Transmeta; // Transmeta - else if (this->ChipID.Vendor == "Geode By NSC") - this->ChipManufacturer = NSC; // National Semiconductor - else if (this->ChipID.Vendor == "Sun") - this->ChipManufacturer = Sun; // Sun Microelectronics - else if (this->ChipID.Vendor == "IBM") - this->ChipManufacturer = IBM; // IBM Microelectronics - else if (this->ChipID.Vendor == "Hewlett-Packard") - this->ChipManufacturer = HP; // Hewlett-Packard - else if (this->ChipID.Vendor == "Motorola") - this->ChipManufacturer = Motorola; // Motorola Microelectronics - else if (family.substr(0, 7) == "PA-RISC") - this->ChipManufacturer = HP; // Hewlett-Packard - else - this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUIdentity() -{ -#if USE_CPUID - int localCPUVendor[4]; - int localCPUSignature[4]; - - if (!call_cpuid(0, localCPUVendor)) { - return false; - } - if (!call_cpuid(1, localCPUSignature)) { - return false; - } - - // Process the returned information. - // ; eax = 0 --> eax: maximum value of CPUID instruction. - // ; ebx: part 1 of 3; CPU signature. - // ; edx: part 2 of 3; CPU signature. - // ; ecx: part 3 of 3; CPU signature. - char vbuf[13]; - memcpy(&(vbuf[0]), &(localCPUVendor[1]), sizeof(int)); - memcpy(&(vbuf[4]), &(localCPUVendor[3]), sizeof(int)); - memcpy(&(vbuf[8]), &(localCPUVendor[2]), sizeof(int)); - vbuf[12] = '\0'; - this->ChipID.Vendor = vbuf; - - // Retrieve the family of CPU present. - // ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, - // bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision - // ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, - // 15..8 - CFLUSH chunk size , 7..0 - brand ID - // ; edx: CPU feature flags - this->ChipID.ExtendedFamily = - ((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used - this->ChipID.ExtendedModel = - ((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used - this->ChipID.Type = - ((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used - this->ChipID.Family = - ((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used - this->ChipID.Model = - ((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used - this->ChipID.Revision = - ((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used - - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUCacheDetails() -{ -#if USE_CPUID - int L1Cache[4] = { 0, 0, 0, 0 }; - int L2Cache[4] = { 0, 0, 0, 0 }; - - // Check to see if what we are about to do is supported... - if (RetrieveCPUExtendedLevelSupport(0x80000005)) { - if (!call_cpuid(0x80000005, L1Cache)) { - return false; - } - // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as - // data cache size from edx: bits 31..24. - this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24); - this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24); - } else { - // Store -1 to indicate the cache could not be queried. - this->Features.L1CacheSize = -1; - } - - // Check to see if what we are about to do is supported... - if (RetrieveCPUExtendedLevelSupport(0x80000006)) { - if (!call_cpuid(0x80000006, L2Cache)) { - return false; - } - // Save the L2 unified cache size (in KB) from ecx: bits 31..16. - this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16); - } else { - // Store -1 to indicate the cache could not be queried. - this->Features.L2CacheSize = -1; - } - - // Define L3 as being not present as we cannot test for it. - this->Features.L3CacheSize = -1; - -#endif - - // Return failure if we cannot detect either cache with this method. - return ((this->Features.L1CacheSize == -1) && - (this->Features.L2CacheSize == -1)) - ? false - : true; -} - -/** */ -bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails() -{ -#if USE_CPUID - int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, - L2Unified = -1, L3Unified = -1; - int TLBCacheData[4] = { 0, 0, 0, 0 }; - int TLBPassCounter = 0; - int TLBCacheUnit = 0; - - do { - if (!call_cpuid(2, TLBCacheData)) { - return false; - } - - int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16); - (void)bob; - // Process the returned TLB and cache information. - for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter++) { - // First of all - decide which unit we are dealing with. - switch (nCounter) { - // eax: bits 8..15 : bits 16..23 : bits 24..31 - case 0: - TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); - break; - case 1: - TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); - break; - case 2: - TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); - break; - - // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 - case 3: - TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); - break; - case 4: - TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); - break; - case 5: - TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); - break; - case 6: - TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); - break; - - // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 - case 7: - TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); - break; - case 8: - TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); - break; - case 9: - TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); - break; - case 10: - TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); - break; - - // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 - case 11: - TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); - break; - case 12: - TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); - break; - case 13: - TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); - break; - case 14: - TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); - break; - - // Default case - an error has occurred. - default: - return false; - } - - // Now process the resulting unit to see what it means.... - switch (TLBCacheUnit) { - case 0x00: - break; - case 0x01: - STORE_TLBCACHE_INFO(TLBCode, 4); - break; - case 0x02: - STORE_TLBCACHE_INFO(TLBCode, 4096); - break; - case 0x03: - STORE_TLBCACHE_INFO(TLBData, 4); - break; - case 0x04: - STORE_TLBCACHE_INFO(TLBData, 4096); - break; - case 0x06: - STORE_TLBCACHE_INFO(L1Code, 8); - break; - case 0x08: - STORE_TLBCACHE_INFO(L1Code, 16); - break; - case 0x0a: - STORE_TLBCACHE_INFO(L1Data, 8); - break; - case 0x0c: - STORE_TLBCACHE_INFO(L1Data, 16); - break; - case 0x10: - STORE_TLBCACHE_INFO(L1Data, 16); - break; // <-- FIXME: IA-64 Only - case 0x15: - STORE_TLBCACHE_INFO(L1Code, 16); - break; // <-- FIXME: IA-64 Only - case 0x1a: - STORE_TLBCACHE_INFO(L2Unified, 96); - break; // <-- FIXME: IA-64 Only - case 0x22: - STORE_TLBCACHE_INFO(L3Unified, 512); - break; - case 0x23: - STORE_TLBCACHE_INFO(L3Unified, 1024); - break; - case 0x25: - STORE_TLBCACHE_INFO(L3Unified, 2048); - break; - case 0x29: - STORE_TLBCACHE_INFO(L3Unified, 4096); - break; - case 0x39: - STORE_TLBCACHE_INFO(L2Unified, 128); - break; - case 0x3c: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x40: - STORE_TLBCACHE_INFO(L2Unified, 0); - break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 - // core). - case 0x41: - STORE_TLBCACHE_INFO(L2Unified, 128); - break; - case 0x42: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x43: - STORE_TLBCACHE_INFO(L2Unified, 512); - break; - case 0x44: - STORE_TLBCACHE_INFO(L2Unified, 1024); - break; - case 0x45: - STORE_TLBCACHE_INFO(L2Unified, 2048); - break; - case 0x50: - STORE_TLBCACHE_INFO(TLBCode, 4096); - break; - case 0x51: - STORE_TLBCACHE_INFO(TLBCode, 4096); - break; - case 0x52: - STORE_TLBCACHE_INFO(TLBCode, 4096); - break; - case 0x5b: - STORE_TLBCACHE_INFO(TLBData, 4096); - break; - case 0x5c: - STORE_TLBCACHE_INFO(TLBData, 4096); - break; - case 0x5d: - STORE_TLBCACHE_INFO(TLBData, 4096); - break; - case 0x66: - STORE_TLBCACHE_INFO(L1Data, 8); - break; - case 0x67: - STORE_TLBCACHE_INFO(L1Data, 16); - break; - case 0x68: - STORE_TLBCACHE_INFO(L1Data, 32); - break; - case 0x70: - STORE_TLBCACHE_INFO(L1Trace, 12); - break; - case 0x71: - STORE_TLBCACHE_INFO(L1Trace, 16); - break; - case 0x72: - STORE_TLBCACHE_INFO(L1Trace, 32); - break; - case 0x77: - STORE_TLBCACHE_INFO(L1Code, 16); - break; // <-- FIXME: IA-64 Only - case 0x79: - STORE_TLBCACHE_INFO(L2Unified, 128); - break; - case 0x7a: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x7b: - STORE_TLBCACHE_INFO(L2Unified, 512); - break; - case 0x7c: - STORE_TLBCACHE_INFO(L2Unified, 1024); - break; - case 0x7e: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x81: - STORE_TLBCACHE_INFO(L2Unified, 128); - break; - case 0x82: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x83: - STORE_TLBCACHE_INFO(L2Unified, 512); - break; - case 0x84: - STORE_TLBCACHE_INFO(L2Unified, 1024); - break; - case 0x85: - STORE_TLBCACHE_INFO(L2Unified, 2048); - break; - case 0x88: - STORE_TLBCACHE_INFO(L3Unified, 2048); - break; // <-- FIXME: IA-64 Only - case 0x89: - STORE_TLBCACHE_INFO(L3Unified, 4096); - break; // <-- FIXME: IA-64 Only - case 0x8a: - STORE_TLBCACHE_INFO(L3Unified, 8192); - break; // <-- FIXME: IA-64 Only - case 0x8d: - STORE_TLBCACHE_INFO(L3Unified, 3096); - break; // <-- FIXME: IA-64 Only - case 0x90: - STORE_TLBCACHE_INFO(TLBCode, 262144); - break; // <-- FIXME: IA-64 Only - case 0x96: - STORE_TLBCACHE_INFO(TLBCode, 262144); - break; // <-- FIXME: IA-64 Only - case 0x9b: - STORE_TLBCACHE_INFO(TLBCode, 262144); - break; // <-- FIXME: IA-64 Only - - // Default case - an error has occurred. - default: - return false; - } - } - - // Increment the TLB pass counter. - TLBPassCounter++; - } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter); - - // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... - if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1)) { - this->Features.L1CacheSize = -1; - } else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1)) { - this->Features.L1CacheSize = L1Trace; - } else if ((L1Code != -1) && (L1Data == -1)) { - this->Features.L1CacheSize = L1Code; - } else if ((L1Code == -1) && (L1Data != -1)) { - this->Features.L1CacheSize = L1Data; - } else if ((L1Code != -1) && (L1Data != -1)) { - this->Features.L1CacheSize = L1Code + L1Data; - } else { - this->Features.L1CacheSize = -1; - } - - // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... - if (L2Unified == -1) { - this->Features.L2CacheSize = -1; - } else { - this->Features.L2CacheSize = L2Unified; - } - - // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... - if (L3Unified == -1) { - this->Features.L3CacheSize = -1; - } else { - this->Features.L3CacheSize = L3Unified; - } - - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUClockSpeed() -{ - bool retrieved = false; - -#if defined(_WIN32) - unsigned int uiRepetitions = 1; - unsigned int uiMSecPerRepetition = 50; - __int64 i64Total = 0; - __int64 i64Overhead = 0; - - // Check if the TSC implementation works at all - if (this->Features.HasTSC && - GetCyclesDifference(SystemInformationImplementation::Delay, - uiMSecPerRepetition) > 0) { - for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter++) { - i64Total += GetCyclesDifference(SystemInformationImplementation::Delay, - uiMSecPerRepetition); - i64Overhead += GetCyclesDifference( - SystemInformationImplementation::DelayOverhead, uiMSecPerRepetition); - } - - // Calculate the MHz speed. - i64Total -= i64Overhead; - i64Total /= uiRepetitions; - i64Total /= uiMSecPerRepetition; - i64Total /= 1000; - - // Save the CPU speed. - this->CPUSpeedInMHz = (float)i64Total; - - retrieved = true; - } - - // If RDTSC is not supported, we fallback to trying to read this value - // from the registry: - if (!retrieved) { - HKEY hKey = NULL; - LONG err = - RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, - KEY_READ, &hKey); - - if (ERROR_SUCCESS == err) { - DWORD dwType = 0; - DWORD data = 0; - DWORD dwSize = sizeof(DWORD); - - err = - RegQueryValueExW(hKey, L"~MHz", 0, &dwType, (LPBYTE)&data, &dwSize); - - if (ERROR_SUCCESS == err) { - this->CPUSpeedInMHz = (float)data; - retrieved = true; - } - - RegCloseKey(hKey); - hKey = NULL; - } - } -#endif - - return retrieved; -} - -/** */ -bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed() -{ -#if USE_ASM_INSTRUCTIONS - LARGE_INTEGER liStart, liEnd, liCountsPerSecond; - double dFrequency, dDifference; - - // Attempt to get a starting tick count. - QueryPerformanceCounter(&liStart); - - __try { - _asm { - mov eax, 0x80000000 - mov ebx, CLASSICAL_CPU_FREQ_LOOP - Timer_Loop: - bsf ecx,eax - dec ebx - jnz Timer_Loop - } - } __except (1) { - return false; - } - - // Attempt to get a starting tick count. - QueryPerformanceCounter(&liEnd); - - // Get the difference... NB: This is in seconds.... - QueryPerformanceFrequency(&liCountsPerSecond); - dDifference = (((double)liEnd.QuadPart - (double)liStart.QuadPart) / - (double)liCountsPerSecond.QuadPart); - - // Calculate the clock speed. - if (this->ChipID.Family == 3) { - // 80386 processors.... Loop time is 115 cycles! - dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000); - } else if (this->ChipID.Family == 4) { - // 80486 processors.... Loop time is 47 cycles! - dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000); - } else if (this->ChipID.Family == 5) { - // Pentium processors.... Loop time is 43 cycles! - dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000); - } - - // Save the clock speed. - this->Features.CPUSpeed = (int)dFrequency; - - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport( - int CPULevelToCheck) -{ - int cpuinfo[4] = { 0, 0, 0, 0 }; - - // The extended CPUID is supported by various vendors starting with the - // following CPU models: - // - // Manufacturer & Chip Name | Family Model Revision - // - // AMD K6, K6-2 | 5 6 x - // Cyrix GXm, Cyrix III "Joshua" | 5 4 x - // IDT C6-2 | 5 8 x - // VIA Cyrix III | 6 5 x - // Transmeta Crusoe | 5 x x - // Intel Pentium 4 | f x x - // - - // We check to see if a supported processor is present... - if (this->ChipManufacturer == AMD) { - if (this->ChipID.Family < 5) - return false; - if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6)) - return false; - } else if (this->ChipManufacturer == Cyrix) { - if (this->ChipID.Family < 5) - return false; - if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4)) - return false; - if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5)) - return false; - } else if (this->ChipManufacturer == IDT) { - if (this->ChipID.Family < 5) - return false; - if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8)) - return false; - } else if (this->ChipManufacturer == Transmeta) { - if (this->ChipID.Family < 5) - return false; - } else if (this->ChipManufacturer == Intel) { - if (this->ChipID.Family < 0xf) { - return false; - } - } - -#if USE_CPUID - if (!call_cpuid(0x80000000, cpuinfo)) { - return false; - } -#endif - - // Now we have to check the level wanted vs level returned... - int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF); - int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF); - - // Check to see if the level provided is supported... - if (nLevelWanted > nLevelReturn) { - return false; - } - - return true; -} - -/** */ -bool SystemInformationImplementation::RetrieveExtendedCPUFeatures() -{ - - // Check that we are not using an Intel processor as it does not support - // this. - if (this->ChipManufacturer == Intel) { - return false; - } - - // Check to see if what we are about to do is supported... - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000001))) { - return false; - } - -#if USE_CPUID - int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 }; - - if (!call_cpuid(0x80000001, localCPUExtendedFeatures)) { - return false; - } - - // Retrieve the extended features of CPU present. - this->Features.ExtendedFeatures.Has3DNow = - ((localCPUExtendedFeatures[3] & 0x80000000) != - 0); // 3DNow Present --> Bit 31. - this->Features.ExtendedFeatures.Has3DNowPlus = - ((localCPUExtendedFeatures[3] & 0x40000000) != - 0); // 3DNow+ Present -- > Bit 30. - this->Features.ExtendedFeatures.HasSSEMMX = - ((localCPUExtendedFeatures[3] & 0x00400000) != - 0); // SSE MMX Present --> Bit 22. - this->Features.ExtendedFeatures.SupportsMP = - ((localCPUExtendedFeatures[3] & 0x00080000) != - 0); // MP Capable -- > Bit 19. - - // Retrieve AMD specific extended features. - if (this->ChipManufacturer == AMD) { - this->Features.ExtendedFeatures.HasMMXPlus = - ((localCPUExtendedFeatures[3] & 0x00400000) != - 0); // AMD specific: MMX-SSE --> Bit 22 - } - - // Retrieve Cyrix specific extended features. - if (this->ChipManufacturer == Cyrix) { - this->Features.ExtendedFeatures.HasMMXPlus = - ((localCPUExtendedFeatures[3] & 0x01000000) != - 0); // Cyrix specific: Extended MMX --> Bit 24 - } - - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveProcessorSerialNumber() -{ - // Check to see if the processor supports the processor serial number. - if (!this->Features.HasSerial) { - return false; - } - -#if USE_CPUID - int SerialNumber[4]; - - if (!call_cpuid(3, SerialNumber)) { - return false; - } - - // Process the returned information. - // ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: - // Transmeta only ?!? - // ; ecx: middle 32 bits are the processor signature bits - // ; edx: bottom 32 bits are the processor signature bits - char sn[128]; - sprintf(sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x", - ((SerialNumber[1] & 0xff000000) >> 24), - ((SerialNumber[1] & 0x00ff0000) >> 16), - ((SerialNumber[1] & 0x0000ff00) >> 8), - ((SerialNumber[1] & 0x000000ff) >> 0), - ((SerialNumber[2] & 0xff000000) >> 24), - ((SerialNumber[2] & 0x00ff0000) >> 16), - ((SerialNumber[2] & 0x0000ff00) >> 8), - ((SerialNumber[2] & 0x000000ff) >> 0), - ((SerialNumber[3] & 0xff000000) >> 24), - ((SerialNumber[3] & 0x00ff0000) >> 16), - ((SerialNumber[3] & 0x0000ff00) >> 8), - ((SerialNumber[3] & 0x000000ff) >> 0)); - this->ChipID.SerialNumber = sn; - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUPowerManagement() -{ - // Check to see if what we are about to do is supported... - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000007))) { - this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false; - this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false; - this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false; - return false; - } - -#if USE_CPUID - int localCPUPowerManagement[4] = { 0, 0, 0, 0 }; - - if (!call_cpuid(0x80000007, localCPUPowerManagement)) { - return false; - } - - // Check for the power management capabilities of the CPU. - this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = - ((localCPUPowerManagement[3] & 0x00000001) != 0); - this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = - ((localCPUPowerManagement[3] & 0x00000002) != 0); - this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = - ((localCPUPowerManagement[3] & 0x00000004) != 0); - - return true; - -#else - return false; -#endif -} - -#if USE_CPUID -// Used only in USE_CPUID implementation below. -static void SystemInformationStripLeadingSpace(std::string& str) -{ - // Because some manufacturers have leading white space - we have to - // post-process the name. - std::string::size_type pos = str.find_first_not_of(" "); - if (pos != std::string::npos) { - str = str.substr(pos); - } -} -#endif - -/** */ -bool SystemInformationImplementation::RetrieveExtendedCPUIdentity() -{ - // Check to see if what we are about to do is supported... - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000002))) - return false; - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000003))) - return false; - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000004))) - return false; - -#if USE_CPUID - int CPUExtendedIdentity[12]; - - if (!call_cpuid(0x80000002, CPUExtendedIdentity)) { - return false; - } - if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4)) { - return false; - } - if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8)) { - return false; - } - - // Process the returned information. - char nbuf[49]; - memcpy(&(nbuf[0]), &(CPUExtendedIdentity[0]), sizeof(int)); - memcpy(&(nbuf[4]), &(CPUExtendedIdentity[1]), sizeof(int)); - memcpy(&(nbuf[8]), &(CPUExtendedIdentity[2]), sizeof(int)); - memcpy(&(nbuf[12]), &(CPUExtendedIdentity[3]), sizeof(int)); - memcpy(&(nbuf[16]), &(CPUExtendedIdentity[4]), sizeof(int)); - memcpy(&(nbuf[20]), &(CPUExtendedIdentity[5]), sizeof(int)); - memcpy(&(nbuf[24]), &(CPUExtendedIdentity[6]), sizeof(int)); - memcpy(&(nbuf[28]), &(CPUExtendedIdentity[7]), sizeof(int)); - memcpy(&(nbuf[32]), &(CPUExtendedIdentity[8]), sizeof(int)); - memcpy(&(nbuf[36]), &(CPUExtendedIdentity[9]), sizeof(int)); - memcpy(&(nbuf[40]), &(CPUExtendedIdentity[10]), sizeof(int)); - memcpy(&(nbuf[44]), &(CPUExtendedIdentity[11]), sizeof(int)); - nbuf[48] = '\0'; - this->ChipID.ProcessorName = nbuf; - this->ChipID.ModelName = nbuf; - - // Because some manufacturers have leading white space - we have to - // post-process the name. - SystemInformationStripLeadingSpace(this->ChipID.ProcessorName); - return true; -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveClassicalCPUIdentity() -{ - // Start by decided which manufacturer we are using.... - switch (this->ChipManufacturer) { - case Intel: - // Check the family / model / revision to determine the CPU ID. - switch (this->ChipID.Family) { - case 3: - this->ChipID.ProcessorName = "Newer i80386 family"; - break; - case 4: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "i80486DX-25/33"; - break; - case 1: - this->ChipID.ProcessorName = "i80486DX-50"; - break; - case 2: - this->ChipID.ProcessorName = "i80486SX"; - break; - case 3: - this->ChipID.ProcessorName = "i80486DX2"; - break; - case 4: - this->ChipID.ProcessorName = "i80486SL"; - break; - case 5: - this->ChipID.ProcessorName = "i80486SX2"; - break; - case 7: - this->ChipID.ProcessorName = "i80486DX2 WriteBack"; - break; - case 8: - this->ChipID.ProcessorName = "i80486DX4"; - break; - case 9: - this->ChipID.ProcessorName = "i80486DX4 WriteBack"; - break; - default: - this->ChipID.ProcessorName = "Unknown 80486 family"; - return false; - } - break; - case 5: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "P5 A-Step"; - break; - case 1: - this->ChipID.ProcessorName = "P5"; - break; - case 2: - this->ChipID.ProcessorName = "P54C"; - break; - case 3: - this->ChipID.ProcessorName = "P24T OverDrive"; - break; - case 4: - this->ChipID.ProcessorName = "P55C"; - break; - case 7: - this->ChipID.ProcessorName = "P54C"; - break; - case 8: - this->ChipID.ProcessorName = "P55C (0.25micron)"; - break; - default: - this->ChipID.ProcessorName = "Unknown Pentium family"; - return false; - } - break; - case 6: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "P6 A-Step"; - break; - case 1: - this->ChipID.ProcessorName = "P6"; - break; - case 3: - this->ChipID.ProcessorName = "Pentium II (0.28 micron)"; - break; - case 5: - this->ChipID.ProcessorName = "Pentium II (0.25 micron)"; - break; - case 6: - this->ChipID.ProcessorName = "Pentium II With On-Die L2 Cache"; - break; - case 7: - this->ChipID.ProcessorName = "Pentium III (0.25 micron)"; - break; - case 8: - this->ChipID.ProcessorName = - "Pentium III (0.18 micron) With 256 KB On-Die L2 Cache "; - break; - case 0xa: - this->ChipID.ProcessorName = - "Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache "; - break; - case 0xb: - this->ChipID.ProcessorName = "Pentium III (0.13 micron) With " - "256 Or 512 KB On-Die L2 Cache "; - break; - case 23: - this->ChipID.ProcessorName = - "Intel(R) Core(TM)2 Duo CPU T9500 @ 2.60GHz"; - break; - default: - this->ChipID.ProcessorName = "Unknown P6 family"; - return false; - } - break; - case 7: - this->ChipID.ProcessorName = "Intel Merced (IA-64)"; - break; - case 0xf: - // Check the extended family bits... - switch (this->ChipID.ExtendedFamily) { - case 0: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; - break; - case 1: - this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; - break; - case 2: - this->ChipID.ProcessorName = "Pentium IV (0.13 micron)"; - break; - default: - this->ChipID.ProcessorName = "Unknown Pentium 4 family"; - return false; - } - break; - case 1: - this->ChipID.ProcessorName = "Intel McKinley (IA-64)"; - break; - default: - this->ChipID.ProcessorName = "Pentium"; - } - break; - default: - this->ChipID.ProcessorName = "Unknown Intel family"; - return false; - } - break; - - case AMD: - // Check the family / model / revision to determine the CPU ID. - switch (this->ChipID.Family) { - case 4: - switch (this->ChipID.Model) { - case 3: - this->ChipID.ProcessorName = "80486DX2"; - break; - case 7: - this->ChipID.ProcessorName = "80486DX2 WriteBack"; - break; - case 8: - this->ChipID.ProcessorName = "80486DX4"; - break; - case 9: - this->ChipID.ProcessorName = "80486DX4 WriteBack"; - break; - case 0xe: - this->ChipID.ProcessorName = "5x86"; - break; - case 0xf: - this->ChipID.ProcessorName = "5x86WB"; - break; - default: - this->ChipID.ProcessorName = "Unknown 80486 family"; - return false; - } - break; - case 5: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "SSA5 (PR75, PR90 = PR100)"; - break; - case 1: - this->ChipID.ProcessorName = "5k86 (PR120 = PR133)"; - break; - case 2: - this->ChipID.ProcessorName = "5k86 (PR166)"; - break; - case 3: - this->ChipID.ProcessorName = "5k86 (PR200)"; - break; - case 6: - this->ChipID.ProcessorName = "K6 (0.30 micron)"; - break; - case 7: - this->ChipID.ProcessorName = "K6 (0.25 micron)"; - break; - case 8: - this->ChipID.ProcessorName = "K6-2"; - break; - case 9: - this->ChipID.ProcessorName = "K6-III"; - break; - case 0xd: - this->ChipID.ProcessorName = "K6-2+ or K6-III+ (0.18 micron)"; - break; - default: - this->ChipID.ProcessorName = "Unknown 80586 family"; - return false; - } - break; - case 6: - switch (this->ChipID.Model) { - case 1: - this->ChipID.ProcessorName = "Athlon- (0.25 micron)"; - break; - case 2: - this->ChipID.ProcessorName = "Athlon- (0.18 micron)"; - break; - case 3: - this->ChipID.ProcessorName = "Duron- (SF core)"; - break; - case 4: - this->ChipID.ProcessorName = "Athlon- (Thunderbird core)"; - break; - case 6: - this->ChipID.ProcessorName = "Athlon- (Palomino core)"; - break; - case 7: - this->ChipID.ProcessorName = "Duron- (Morgan core)"; - break; - case 8: - if (this->Features.ExtendedFeatures.SupportsMP) - this->ChipID.ProcessorName = "Athlon - MP (Thoroughbred core)"; - else - this->ChipID.ProcessorName = "Athlon - XP (Thoroughbred core)"; - break; - default: - this->ChipID.ProcessorName = "Unknown K7 family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown AMD family"; - return false; - } - break; - - case Transmeta: - switch (this->ChipID.Family) { - case 5: - switch (this->ChipID.Model) { - case 4: - this->ChipID.ProcessorName = "Crusoe TM3x00 and TM5x00"; - break; - default: - this->ChipID.ProcessorName = "Unknown Crusoe family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown Transmeta family"; - return false; - } - break; - - case Rise: - switch (this->ChipID.Family) { - case 5: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "mP6 (0.25 micron)"; - break; - case 2: - this->ChipID.ProcessorName = "mP6 (0.18 micron)"; - break; - default: - this->ChipID.ProcessorName = "Unknown Rise family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown Rise family"; - return false; - } - break; - - case UMC: - switch (this->ChipID.Family) { - case 4: - switch (this->ChipID.Model) { - case 1: - this->ChipID.ProcessorName = "U5D"; - break; - case 2: - this->ChipID.ProcessorName = "U5S"; - break; - default: - this->ChipID.ProcessorName = "Unknown UMC family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown UMC family"; - return false; - } - break; - - case IDT: - switch (this->ChipID.Family) { - case 5: - switch (this->ChipID.Model) { - case 4: - this->ChipID.ProcessorName = "C6"; - break; - case 8: - this->ChipID.ProcessorName = "C2"; - break; - case 9: - this->ChipID.ProcessorName = "C3"; - break; - default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; - return false; - } - break; - case 6: - switch (this->ChipID.Model) { - case 6: - this->ChipID.ProcessorName = "VIA Cyrix III - Samuel"; - break; - default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; - return false; - } - break; - - case Cyrix: - switch (this->ChipID.Family) { - case 4: - switch (this->ChipID.Model) { - case 4: - this->ChipID.ProcessorName = "MediaGX GX = GXm"; - break; - case 9: - this->ChipID.ProcessorName = "5x86"; - break; - default: - this->ChipID.ProcessorName = "Unknown Cx5x86 family"; - return false; - } - break; - case 5: - switch (this->ChipID.Model) { - case 2: - this->ChipID.ProcessorName = "Cx6x86"; - break; - case 4: - this->ChipID.ProcessorName = "MediaGX GXm"; - break; - default: - this->ChipID.ProcessorName = "Unknown Cx6x86 family"; - return false; - } - break; - case 6: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "6x86MX"; - break; - case 5: - this->ChipID.ProcessorName = "Cyrix M2 Core"; - break; - case 6: - this->ChipID.ProcessorName = "WinChip C5A Core"; - break; - case 7: - this->ChipID.ProcessorName = "WinChip C5B\\C5C Core"; - break; - case 8: - this->ChipID.ProcessorName = "WinChip C5C-T Core"; - break; - default: - this->ChipID.ProcessorName = "Unknown 6x86MX\\Cyrix III family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown Cyrix family"; - return false; - } - break; - - case NexGen: - switch (this->ChipID.Family) { - case 5: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "Nx586 or Nx586FPU"; - break; - default: - this->ChipID.ProcessorName = "Unknown NexGen family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown NexGen family"; - return false; - } - break; - - case NSC: - this->ChipID.ProcessorName = "Cx486SLC \\ DLC \\ Cx486S A-Step"; - break; - - case Sun: - case IBM: - case Motorola: - case HP: - case UnknownManufacturer: - default: - this->ChipID.ProcessorName = - "Unknown family"; // We cannot identify the processor. - return false; - } - - return true; -} - -/** Extract a value from the CPUInfo file */ -std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile( - std::string buffer, const char* word, size_t init) -{ - size_t pos = buffer.find(word, init); - if (pos != std::string::npos) { - this->CurrentPositionInFile = pos; - pos = buffer.find(":", pos); - size_t pos2 = buffer.find("\n", pos); - if (pos != std::string::npos && pos2 != std::string::npos) { - // It may happen that the beginning matches, but this is still not the - // requested key. - // An example is looking for "cpu" when "cpu family" comes first. So we - // check that - // we have only spaces from here to pos, otherwise we search again. - for (size_t i = this->CurrentPositionInFile + strlen(word); i < pos; - ++i) { - if (buffer[i] != ' ' && buffer[i] != '\t') { - return this->ExtractValueFromCpuInfoFile(buffer, word, pos2); - } - } - return buffer.substr(pos + 2, pos2 - pos - 2); - } - } - this->CurrentPositionInFile = std::string::npos; - return ""; -} - -/** Query for the cpu status */ -bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() -{ - this->NumberOfLogicalCPU = 0; - this->NumberOfPhysicalCPU = 0; - std::string buffer; - - FILE* fd = fopen("/proc/cpuinfo", "r"); - if (!fd) { - std::cout << "Problem opening /proc/cpuinfo" << std::endl; - return false; - } - - size_t fileSize = 0; - while (!feof(fd)) { - buffer += static_cast(fgetc(fd)); - fileSize++; - } - fclose(fd); - buffer.resize(fileSize - 2); - // Number of logical CPUs (combination of multiple processors, multi-core - // and SMT) - size_t pos = buffer.find("processor\t"); - while (pos != std::string::npos) { - this->NumberOfLogicalCPU++; - pos = buffer.find("processor\t", pos + 1); - } - -#ifdef __linux - // Count sockets. - std::set PhysicalIDs; - std::string idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id"); - while (this->CurrentPositionInFile != std::string::npos) { - int id = atoi(idc.c_str()); - PhysicalIDs.insert(id); - idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id", - this->CurrentPositionInFile + 1); - } - uint64_t NumberOfSockets = PhysicalIDs.size(); - NumberOfSockets = std::max(NumberOfSockets, (uint64_t)1); - // Physical ids returned by Linux don't distinguish cores. - // We want to record the total number of cores in this->NumberOfPhysicalCPU - // (checking only the first proc) - std::string Cores = this->ExtractValueFromCpuInfoFile(buffer, "cpu cores"); - unsigned int NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str()); - NumberOfCoresPerSocket = std::max(NumberOfCoresPerSocket, 1u); - this->NumberOfPhysicalCPU = - NumberOfCoresPerSocket * (unsigned int)NumberOfSockets; - -#else // __CYGWIN__ - // does not have "physical id" entries, neither "cpu cores" - // this has to be fixed for hyper-threading. - std::string cpucount = - this->ExtractValueFromCpuInfoFile(buffer, "cpu count"); - this->NumberOfPhysicalCPU = this->NumberOfLogicalCPU = - atoi(cpucount.c_str()); -#endif - // gotta have one, and if this is 0 then we get a / by 0n - // better to have a bad answer than a crash - if (this->NumberOfPhysicalCPU <= 0) { - this->NumberOfPhysicalCPU = 1; - } - // LogicalProcessorsPerPhysical>1 => SMT. - this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = - this->NumberOfLogicalCPU / this->NumberOfPhysicalCPU; - - // CPU speed (checking only the first processor) - std::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "cpu MHz"); - if (!CPUSpeed.empty()) { - this->CPUSpeedInMHz = static_cast(atof(CPUSpeed.c_str())); - } -#ifdef __linux - else { - // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal - CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "Cpu0ClkTck"); - this->CPUSpeedInMHz = - static_cast(strtoull(CPUSpeed.c_str(), 0, 16)) / 1000000.0f; - } -#endif - - // Chip family - std::string familyStr = - this->ExtractValueFromCpuInfoFile(buffer, "cpu family"); - if (familyStr.empty()) { - familyStr = this->ExtractValueFromCpuInfoFile(buffer, "CPU architecture"); - } - this->ChipID.Family = atoi(familyStr.c_str()); - - // Chip Vendor - this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer, "vendor_id"); - this->FindManufacturer(familyStr); - - // second try for setting family - if (this->ChipID.Family == 0 && this->ChipManufacturer == HP) { - if (familyStr == "PA-RISC 1.1a") - this->ChipID.Family = 0x11a; - else if (familyStr == "PA-RISC 2.0") - this->ChipID.Family = 0x200; - // If you really get CMake to work on a machine not belonging to - // any of those families I owe you a dinner if you get it to - // contribute nightly builds regularly. - } - - // Chip Model - this->ChipID.Model = - atoi(this->ExtractValueFromCpuInfoFile(buffer, "model").c_str()); - if (!this->RetrieveClassicalCPUIdentity()) { - // Some platforms (e.g. PA-RISC) tell us their CPU name here. - // Note: x86 does not. - std::string cpuname = this->ExtractValueFromCpuInfoFile(buffer, "cpu"); - if (!cpuname.empty()) { - this->ChipID.ProcessorName = cpuname; - } - } - - // Chip revision - std::string cpurev = this->ExtractValueFromCpuInfoFile(buffer, "stepping"); - if (cpurev.empty()) { - cpurev = this->ExtractValueFromCpuInfoFile(buffer, "CPU revision"); - } - this->ChipID.Revision = atoi(cpurev.c_str()); - - // Chip Model Name - this->ChipID.ModelName = - this->ExtractValueFromCpuInfoFile(buffer, "model name").c_str(); - - // L1 Cache size - // Different architectures may show different names for the caches. - // Sum up everything we find. - std::vector cachename; - cachename.clear(); - - cachename.push_back("cache size"); // e.g. x86 - cachename.push_back("I-cache"); // e.g. PA-RISC - cachename.push_back("D-cache"); // e.g. PA-RISC - - this->Features.L1CacheSize = 0; - for (size_t index = 0; index < cachename.size(); index++) { - std::string cacheSize = - this->ExtractValueFromCpuInfoFile(buffer, cachename[index]); - if (!cacheSize.empty()) { - pos = cacheSize.find(" KB"); - if (pos != std::string::npos) { - cacheSize = cacheSize.substr(0, pos); - } - this->Features.L1CacheSize += atoi(cacheSize.c_str()); - } - } - - // processor feature flags (probably x86 specific) - std::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer, "flags"); - if (!cpurev.empty()) { - // now we can match every flags as space + flag + space - cpuflags = " " + cpuflags + " "; - if ((cpuflags.find(" fpu ") != std::string::npos)) { - this->Features.HasFPU = true; - } - if ((cpuflags.find(" tsc ") != std::string::npos)) { - this->Features.HasTSC = true; - } - if ((cpuflags.find(" mmx ") != std::string::npos)) { - this->Features.HasMMX = true; - } - if ((cpuflags.find(" sse ") != std::string::npos)) { - this->Features.HasSSE = true; - } - if ((cpuflags.find(" sse2 ") != std::string::npos)) { - this->Features.HasSSE2 = true; - } - if ((cpuflags.find(" apic ") != std::string::npos)) { - this->Features.HasAPIC = true; - } - if ((cpuflags.find(" cmov ") != std::string::npos)) { - this->Features.HasCMOV = true; - } - if ((cpuflags.find(" mtrr ") != std::string::npos)) { - this->Features.HasMTRR = true; - } - if ((cpuflags.find(" acpi ") != std::string::npos)) { - this->Features.HasACPI = true; - } - if ((cpuflags.find(" 3dnow ") != std::string::npos)) { - this->Features.ExtendedFeatures.Has3DNow = true; - } - } - - return true; -} - -bool SystemInformationImplementation::QueryProcessorBySysconf() -{ -#if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN) -// IRIX names this slightly different -#define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN -#endif - -#ifdef _SC_NPROCESSORS_ONLN - long c = sysconf(_SC_NPROCESSORS_ONLN); - if (c <= 0) { - return false; - } - - this->NumberOfPhysicalCPU = static_cast(c); - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryProcessor() -{ - return this->QueryProcessorBySysconf(); -} - -/** -Get total system RAM in units of KiB. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryTotal() -{ -#if defined(_WIN32) -#if defined(_MSC_VER) && _MSC_VER < 1300 - MEMORYSTATUS stat; - stat.dwLength = sizeof(stat); - GlobalMemoryStatus(&stat); - return stat.dwTotalPhys / 1024; -#else - MEMORYSTATUSEX statex; - statex.dwLength = sizeof(statex); - GlobalMemoryStatusEx(&statex); - return statex.ullTotalPhys / 1024; -#endif -#elif defined(__linux) - SystemInformation::LongLong memTotal = 0; - int ierr = GetFieldFromFile("/proc/meminfo", "MemTotal:", memTotal); - if (ierr) { - return -1; - } - return memTotal; -#elif defined(__APPLE__) - uint64_t mem; - size_t len = sizeof(mem); - int ierr = sysctlbyname("hw.memsize", &mem, &len, KWSYS_NULLPTR, 0); - if (ierr) { - return -1; - } - return mem / 1024; -#else - return 0; -#endif -} - -/** -Get total system RAM in units of KiB. This may differ from the -host total if a host-wide resource limit is applied. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryAvailable( - const char* hostLimitEnvVarName) -{ - SystemInformation::LongLong memTotal = this->GetHostMemoryTotal(); - - // the following mechanism is provided for systems that - // apply resource limits across groups of processes. - // this is of use on certain SMP systems (eg. SGI UV) - // where the host has a large amount of ram but a given user's - // access to it is severely restricted. The system will - // apply a limit across a set of processes. Units are in KiB. - if (hostLimitEnvVarName) { - const char* hostLimitEnvVarValue = getenv(hostLimitEnvVarName); - if (hostLimitEnvVarValue) { - SystemInformation::LongLong hostLimit = - atoLongLong(hostLimitEnvVarValue); - if (hostLimit > 0) { - memTotal = min(hostLimit, memTotal); - } - } - } - - return memTotal; -} - -/** -Get total system RAM in units of KiB. This may differ from the -host total if a per-process resource limit is applied. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetProcMemoryAvailable( - const char* hostLimitEnvVarName, const char* procLimitEnvVarName) -{ - SystemInformation::LongLong memAvail = - this->GetHostMemoryAvailable(hostLimitEnvVarName); - - // the following mechanism is provide for systems where rlimits - // are not employed. Units are in KiB. - if (procLimitEnvVarName) { - const char* procLimitEnvVarValue = getenv(procLimitEnvVarName); - if (procLimitEnvVarValue) { - SystemInformation::LongLong procLimit = - atoLongLong(procLimitEnvVarValue); - if (procLimit > 0) { - memAvail = min(procLimit, memAvail); - } - } - } - -#if defined(__linux) - int ierr; - ResourceLimitType rlim; - ierr = GetResourceLimit(RLIMIT_DATA, &rlim); - if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); - } - - ierr = GetResourceLimit(RLIMIT_AS, &rlim); - if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); - } -#elif defined(__APPLE__) - struct rlimit rlim; - int ierr; - ierr = getrlimit(RLIMIT_DATA, &rlim); - if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); - } - - ierr = getrlimit(RLIMIT_RSS, &rlim); - if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); - } -#endif - - return memAvail; -} - -/** -Get RAM used by all processes in the host, in units of KiB. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryUsed() -{ -#if defined(_WIN32) -#if defined(_MSC_VER) && _MSC_VER < 1300 - MEMORYSTATUS stat; - stat.dwLength = sizeof(stat); - GlobalMemoryStatus(&stat); - return (stat.dwTotalPhys - stat.dwAvailPhys) / 1024; -#else - MEMORYSTATUSEX statex; - statex.dwLength = sizeof(statex); - GlobalMemoryStatusEx(&statex); - return (statex.ullTotalPhys - statex.ullAvailPhys) / 1024; -#endif -#elif defined(__linux) - // First try to use MemAvailable, but it only works on newer kernels - const char* names2[3] = { "MemTotal:", "MemAvailable:", NULL }; - SystemInformation::LongLong values2[2] = { SystemInformation::LongLong(0) }; - int ierr = GetFieldsFromFile("/proc/meminfo", names2, values2); - if (ierr) { - const char* names4[5] = { "MemTotal:", "MemFree:", "Buffers:", "Cached:", - NULL }; - SystemInformation::LongLong values4[4] = { SystemInformation::LongLong( - 0) }; - ierr = GetFieldsFromFile("/proc/meminfo", names4, values4); - if (ierr) { - return ierr; - } - SystemInformation::LongLong& memTotal = values4[0]; - SystemInformation::LongLong& memFree = values4[1]; - SystemInformation::LongLong& memBuffers = values4[2]; - SystemInformation::LongLong& memCached = values4[3]; - return memTotal - memFree - memBuffers - memCached; - } - SystemInformation::LongLong& memTotal = values2[0]; - SystemInformation::LongLong& memAvail = values2[1]; - return memTotal - memAvail; -#elif defined(__APPLE__) - SystemInformation::LongLong psz = getpagesize(); - if (psz < 1) { - return -1; - } - const char* names[3] = { "Pages wired down:", "Pages active:", - KWSYS_NULLPTR }; - SystemInformation::LongLong values[2] = { SystemInformation::LongLong(0) }; - int ierr = GetFieldsFromCommand("vm_stat", names, values); - if (ierr) { - return -1; - } - SystemInformation::LongLong& vmWired = values[0]; - SystemInformation::LongLong& vmActive = values[1]; - return ((vmActive + vmWired) * psz) / 1024; -#else - return 0; -#endif -} - -/** -Get system RAM used by the process associated with the given -process id in units of KiB. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetProcMemoryUsed() -{ -#if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI) - long pid = GetCurrentProcessId(); - HANDLE hProc; - hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); - if (hProc == 0) { - return -1; - } - PROCESS_MEMORY_COUNTERS pmc; - int ok = GetProcessMemoryInfo(hProc, &pmc, sizeof(pmc)); - CloseHandle(hProc); - if (!ok) { - return -2; - } - return pmc.WorkingSetSize / 1024; -#elif defined(__linux) - SystemInformation::LongLong memUsed = 0; - int ierr = GetFieldFromFile("/proc/self/status", "VmRSS:", memUsed); - if (ierr) { - return -1; - } - return memUsed; -#elif defined(__APPLE__) - SystemInformation::LongLong memUsed = 0; - pid_t pid = getpid(); - std::ostringstream oss; - oss << "ps -o rss= -p " << pid; - FILE* file = popen(oss.str().c_str(), "r"); - if (file == KWSYS_NULLPTR) { - return -1; - } - oss.str(""); - while (!feof(file) && !ferror(file)) { - char buf[256] = { '\0' }; - errno = 0; - size_t nRead = fread(buf, 1, 256, file); - if (ferror(file) && (errno == EINTR)) { - clearerr(file); - } - if (nRead) - oss << buf; - } - int ierr = ferror(file); - pclose(file); - if (ierr) { - return -2; - } - std::istringstream iss(oss.str()); - iss >> memUsed; - return memUsed; -#else - return 0; -#endif -} - -double SystemInformationImplementation::GetLoadAverage() -{ -#if defined(KWSYS_CXX_HAS_GETLOADAVG) - double loadavg[3] = { 0.0, 0.0, 0.0 }; - if (getloadavg(loadavg, 3) > 0) { - return loadavg[0]; - } - return -0.0; -#elif defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes) - // Old windows.h headers do not provide GetSystemTimes. - typedef BOOL(WINAPI * GetSystemTimesType)(LPFILETIME, LPFILETIME, - LPFILETIME); - static GetSystemTimesType pGetSystemTimes = - (GetSystemTimesType)GetProcAddress(GetModuleHandleW(L"kernel32"), - "GetSystemTimes"); - FILETIME idleTime, kernelTime, userTime; - if (pGetSystemTimes && pGetSystemTimes(&idleTime, &kernelTime, &userTime)) { - unsigned __int64 const idleTicks = fileTimeToUInt64(idleTime); - unsigned __int64 const totalTicks = - fileTimeToUInt64(kernelTime) + fileTimeToUInt64(userTime); - return calculateCPULoad(idleTicks, totalTicks) * GetNumberOfPhysicalCPU(); - } - return -0.0; -#else - // Not implemented on this platform. - return -0.0; -#endif -} - -/** -Get the process id of the running process. -*/ -SystemInformation::LongLong SystemInformationImplementation::GetProcessId() -{ -#if defined(_WIN32) - return GetCurrentProcessId(); -#elif defined(__linux) || defined(__APPLE__) - return getpid(); -#else - return -1; -#endif -} - -/** -return current program stack in a string -demangle cxx symbols if possible. -*/ -std::string SystemInformationImplementation::GetProgramStack(int firstFrame, - int wholePath) -{ - std::string programStack = "" -#if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) - "WARNING: The stack could not be examined " - "because backtrace is not supported.\n" -#elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD) - "WARNING: The stack trace will not use advanced " - "capabilities because this is a release build.\n" -#else -#if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) - "WARNING: Function names will not be demangled " - "because " - "dladdr is not available.\n" -#endif -#if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) - "WARNING: Function names will not be demangled " - "because cxxabi is not available.\n" -#endif -#endif - ; - - std::ostringstream oss; -#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) - void* stackSymbols[256]; - int nFrames = backtrace(stackSymbols, 256); - for (int i = firstFrame; i < nFrames; ++i) { - SymbolProperties symProps; - symProps.SetReportPath(wholePath); - symProps.Initialize(stackSymbols[i]); - oss << symProps << std::endl; - } -#else - (void)firstFrame; - (void)wholePath; -#endif - programStack += oss.str(); - - return programStack; -} - -/** -when set print stack trace in response to common signals. -*/ -void SystemInformationImplementation::SetStackTraceOnError(int enable) -{ -#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) - static int saOrigValid = 0; - static struct sigaction saABRTOrig; - static struct sigaction saSEGVOrig; - static struct sigaction saTERMOrig; - static struct sigaction saINTOrig; - static struct sigaction saILLOrig; - static struct sigaction saBUSOrig; - static struct sigaction saFPEOrig; - - if (enable && !saOrigValid) { - // save the current actions - sigaction(SIGABRT, KWSYS_NULLPTR, &saABRTOrig); - sigaction(SIGSEGV, KWSYS_NULLPTR, &saSEGVOrig); - sigaction(SIGTERM, KWSYS_NULLPTR, &saTERMOrig); - sigaction(SIGINT, KWSYS_NULLPTR, &saINTOrig); - sigaction(SIGILL, KWSYS_NULLPTR, &saILLOrig); - sigaction(SIGBUS, KWSYS_NULLPTR, &saBUSOrig); - sigaction(SIGFPE, KWSYS_NULLPTR, &saFPEOrig); - - // enable read, disable write - saOrigValid = 1; - - // install ours - struct sigaction sa; - sa.sa_sigaction = (SigAction)StacktraceSignalHandler; - sa.sa_flags = SA_SIGINFO | SA_RESETHAND; -#ifdef SA_RESTART - sa.sa_flags |= SA_RESTART; -#endif - sigemptyset(&sa.sa_mask); - - sigaction(SIGABRT, &sa, KWSYS_NULLPTR); - sigaction(SIGSEGV, &sa, KWSYS_NULLPTR); - sigaction(SIGTERM, &sa, KWSYS_NULLPTR); - sigaction(SIGINT, &sa, KWSYS_NULLPTR); - sigaction(SIGILL, &sa, KWSYS_NULLPTR); - sigaction(SIGBUS, &sa, KWSYS_NULLPTR); - sigaction(SIGFPE, &sa, KWSYS_NULLPTR); - } else if (!enable && saOrigValid) { - // restore previous actions - sigaction(SIGABRT, &saABRTOrig, KWSYS_NULLPTR); - sigaction(SIGSEGV, &saSEGVOrig, KWSYS_NULLPTR); - sigaction(SIGTERM, &saTERMOrig, KWSYS_NULLPTR); - sigaction(SIGINT, &saINTOrig, KWSYS_NULLPTR); - sigaction(SIGILL, &saILLOrig, KWSYS_NULLPTR); - sigaction(SIGBUS, &saBUSOrig, KWSYS_NULLPTR); - sigaction(SIGFPE, &saFPEOrig, KWSYS_NULLPTR); - - // enable write, disable read - saOrigValid = 0; - } -#else - // avoid warning C4100 - (void)enable; -#endif -} - -bool SystemInformationImplementation::QueryWindowsMemory() -{ -#if defined(_WIN32) -#if defined(_MSC_VER) && _MSC_VER < 1300 - MEMORYSTATUS ms; - unsigned long tv, tp, av, ap; - ms.dwLength = sizeof(ms); - GlobalMemoryStatus(&ms); -#define MEM_VAL(value) dw##value -#else - MEMORYSTATUSEX ms; - DWORDLONG tv, tp, av, ap; - ms.dwLength = sizeof(ms); - if (0 == GlobalMemoryStatusEx(&ms)) { - return 0; - } -#define MEM_VAL(value) ull##value -#endif - tv = ms.MEM_VAL(TotalPageFile); - tp = ms.MEM_VAL(TotalPhys); - av = ms.MEM_VAL(AvailPageFile); - ap = ms.MEM_VAL(AvailPhys); - this->TotalVirtualMemory = tv >> 10 >> 10; - this->TotalPhysicalMemory = tp >> 10 >> 10; - this->AvailableVirtualMemory = av >> 10 >> 10; - this->AvailablePhysicalMemory = ap >> 10 >> 10; - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryLinuxMemory() -{ -#if defined(__linux) - unsigned long tv = 0; - unsigned long tp = 0; - unsigned long av = 0; - unsigned long ap = 0; - - char buffer[1024]; // for reading lines - - int linuxMajor = 0; - int linuxMinor = 0; - - // Find the Linux kernel version first - struct utsname unameInfo; - int errorFlag = uname(&unameInfo); - if (errorFlag != 0) { - std::cout << "Problem calling uname(): " << strerror(errno) << std::endl; - return false; - } - - if (strlen(unameInfo.release) >= 3) { - // release looks like "2.6.3-15mdk-i686-up-4GB" - char majorChar = unameInfo.release[0]; - char minorChar = unameInfo.release[2]; - - if (isdigit(majorChar)) { - linuxMajor = majorChar - '0'; - } - - if (isdigit(minorChar)) { - linuxMinor = minorChar - '0'; - } - } - - FILE* fd = fopen("/proc/meminfo", "r"); - if (!fd) { - std::cout << "Problem opening /proc/meminfo" << std::endl; - return false; - } - - if (linuxMajor >= 3 || ((linuxMajor >= 2) && (linuxMinor >= 6))) { - // new /proc/meminfo format since kernel 2.6.x - // Rigorously, this test should check from the developping version 2.5.x - // that introduced the new format... - - enum - { - mMemTotal, - mMemFree, - mBuffers, - mCached, - mSwapTotal, - mSwapFree - }; - const char* format[6] = { "MemTotal:%lu kB", "MemFree:%lu kB", - "Buffers:%lu kB", "Cached:%lu kB", - "SwapTotal:%lu kB", "SwapFree:%lu kB" }; - bool have[6] = { false, false, false, false, false, false }; - unsigned long value[6]; - int count = 0; - while (fgets(buffer, static_cast(sizeof(buffer)), fd)) { - for (int i = 0; i < 6; ++i) { - if (!have[i] && sscanf(buffer, format[i], &value[i]) == 1) { - have[i] = true; - ++count; - } - } - } - if (count == 6) { - this->TotalPhysicalMemory = value[mMemTotal] / 1024; - this->AvailablePhysicalMemory = - (value[mMemFree] + value[mBuffers] + value[mCached]) / 1024; - this->TotalVirtualMemory = value[mSwapTotal] / 1024; - this->AvailableVirtualMemory = value[mSwapFree] / 1024; - } else { - std::cout << "Problem parsing /proc/meminfo" << std::endl; - fclose(fd); - return false; - } - } else { - // /proc/meminfo format for kernel older than 2.6.x - - unsigned long temp; - unsigned long cachedMem; - unsigned long buffersMem; - // Skip "total: used:..." - char* r = fgets(buffer, static_cast(sizeof(buffer)), fd); - int status = 0; - if (r == buffer) { - status += fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n", &tp, &temp, &ap, - &temp, &buffersMem, &cachedMem); - } - if (status == 6) { - status += fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av); - } - if (status == 9) { - this->TotalVirtualMemory = tv >> 10 >> 10; - this->TotalPhysicalMemory = tp >> 10 >> 10; - this->AvailableVirtualMemory = av >> 10 >> 10; - this->AvailablePhysicalMemory = - (ap + buffersMem + cachedMem) >> 10 >> 10; - } else { - std::cout << "Problem parsing /proc/meminfo" << std::endl; - fclose(fd); - return false; - } - } - fclose(fd); - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryCygwinMemory() -{ -#ifdef __CYGWIN__ - // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin, - // see http://cygwin.com/ml/cygwin/2006-06/msg00350.html - // Therefore just use 4096 as the page size of Windows. - long m = sysconf(_SC_PHYS_PAGES); - if (m < 0) { - return false; - } - this->TotalPhysicalMemory = m >> 8; - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryAIXMemory() -{ -#if defined(_AIX) && defined(_SC_AIX_REALMEM) - long c = sysconf(_SC_AIX_REALMEM); - if (c <= 0) { - return false; - } - - this->TotalPhysicalMemory = c / 1024; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryMemoryBySysconf() -{ -#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) - // Assume the mmap() granularity as returned by _SC_PAGESIZE is also - // the system page size. The only known system where this isn't true - // is Cygwin. - long p = sysconf(_SC_PHYS_PAGES); - long m = sysconf(_SC_PAGESIZE); - - if (p < 0 || m < 0) { - return false; - } - - // assume pagesize is a power of 2 and smaller 1 MiB - size_t pagediv = (1024 * 1024 / m); - - this->TotalPhysicalMemory = p; - this->TotalPhysicalMemory /= pagediv; - -#if defined(_SC_AVPHYS_PAGES) - p = sysconf(_SC_AVPHYS_PAGES); - if (p < 0) { - return false; - } - - this->AvailablePhysicalMemory = p; - this->AvailablePhysicalMemory /= pagediv; -#endif - - return true; -#else - return false; -#endif -} - -/** Query for the memory status */ -bool SystemInformationImplementation::QueryMemory() -{ - return this->QueryMemoryBySysconf(); -} - -/** */ -size_t SystemInformationImplementation::GetTotalVirtualMemory() -{ - return this->TotalVirtualMemory; -} - -/** */ -size_t SystemInformationImplementation::GetAvailableVirtualMemory() -{ - return this->AvailableVirtualMemory; -} - -size_t SystemInformationImplementation::GetTotalPhysicalMemory() -{ - return this->TotalPhysicalMemory; -} - -/** */ -size_t SystemInformationImplementation::GetAvailablePhysicalMemory() -{ - return this->AvailablePhysicalMemory; -} - -/** Get Cycle differences */ -SystemInformation::LongLong -SystemInformationImplementation::GetCyclesDifference(DELAY_FUNC DelayFunction, - unsigned int uiParameter) -{ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) - unsigned __int64 stamp1, stamp2; - - stamp1 = __rdtsc(); - DelayFunction(uiParameter); - stamp2 = __rdtsc(); - - return stamp2 - stamp1; -#elif USE_ASM_INSTRUCTIONS - - unsigned int edx1, eax1; - unsigned int edx2, eax2; - - // Calculate the frequency of the CPU instructions. - __try { - _asm { - push uiParameter ; push parameter param - mov ebx, DelayFunction ; store func in ebx - - RDTSC_INSTRUCTION - - mov esi, eax ; esi = eax - mov edi, edx ; edi = edx - - call ebx ; call the delay functions - - RDTSC_INSTRUCTION - - pop ebx - - mov edx2, edx ; edx2 = edx - mov eax2, eax ; eax2 = eax - - mov edx1, edi ; edx2 = edi - mov eax1, esi ; eax2 = esi - } - } __except (1) { - return -1; - } - - return ((((__int64)edx2 << 32) + eax2) - (((__int64)edx1 << 32) + eax1)); - -#else - (void)DelayFunction; - (void)uiParameter; - return -1; -#endif -} - -/** Compute the delay overhead */ -void SystemInformationImplementation::DelayOverhead(unsigned int uiMS) -{ -#if defined(_WIN32) - LARGE_INTEGER Frequency, StartCounter, EndCounter; - __int64 x; - - // Get the frequency of the high performance counter. - if (!QueryPerformanceFrequency(&Frequency)) { - return; - } - x = Frequency.QuadPart / 1000 * uiMS; - - // Get the starting position of the counter. - QueryPerformanceCounter(&StartCounter); - - do { - // Get the ending position of the counter. - QueryPerformanceCounter(&EndCounter); - } while (EndCounter.QuadPart - StartCounter.QuadPart == x); -#endif - (void)uiMS; -} - -/** Works only for windows */ -bool SystemInformationImplementation::IsSMTSupported() -{ - return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical > 1; -} - -/** Return the APIC Id. Works only for windows. */ -unsigned char SystemInformationImplementation::GetAPICId() -{ - int Regs[4] = { 0, 0, 0, 0 }; - -#if USE_CPUID - if (!this->IsSMTSupported()) { - return static_cast(-1); // HT not supported - } // Logical processor = 1 - call_cpuid(1, Regs); -#endif - - return static_cast((Regs[1] & INITIAL_APIC_ID_BITS) >> 24); -} - -/** Count the number of CPUs. Works only on windows. */ -void SystemInformationImplementation::CPUCountWindows() -{ -#if defined(_WIN32) - this->NumberOfPhysicalCPU = 0; - this->NumberOfLogicalCPU = 0; - - typedef BOOL(WINAPI * GetLogicalProcessorInformationType)( - PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); - static GetLogicalProcessorInformationType pGetLogicalProcessorInformation = - (GetLogicalProcessorInformationType)GetProcAddress( - GetModuleHandleW(L"kernel32"), "GetLogicalProcessorInformation"); - - if (!pGetLogicalProcessorInformation) { - // Fallback to approximate implementation on ancient Windows versions. - SYSTEM_INFO info; - ZeroMemory(&info, sizeof(info)); - GetSystemInfo(&info); - this->NumberOfPhysicalCPU = - static_cast(info.dwNumberOfProcessors); - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; - return; - } - - std::vector ProcInfo; - { - DWORD Length = 0; - DWORD rc = pGetLogicalProcessorInformation(NULL, &Length); - assert(FALSE == rc); - (void)rc; // Silence unused variable warning in Borland C++ 5.81 - assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER); - ProcInfo.resize(Length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); - rc = pGetLogicalProcessorInformation(&ProcInfo[0], &Length); - assert(rc != FALSE); - (void)rc; // Silence unused variable warning in Borland C++ 5.81 - } - - typedef std::vector::iterator - pinfoIt_t; - for (pinfoIt_t it = ProcInfo.begin(); it != ProcInfo.end(); ++it) { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION PInfo = *it; - if (PInfo.Relationship != RelationProcessorCore) { - continue; - } - - std::bitset::digits> ProcMask( - (unsigned long long)PInfo.ProcessorMask); - unsigned int count = (unsigned int)ProcMask.count(); - if (count == 0) { // I think this should never happen, but just to be safe. - continue; - } - this->NumberOfPhysicalCPU++; - this->NumberOfLogicalCPU += (unsigned int)count; - this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = count; - } - this->NumberOfPhysicalCPU = std::max(1u, this->NumberOfPhysicalCPU); - this->NumberOfLogicalCPU = std::max(1u, this->NumberOfLogicalCPU); -#else -#endif -} - -/** Return the number of logical CPUs on the system */ -unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU() -{ - return this->NumberOfLogicalCPU; -} - -/** Return the number of physical CPUs on the system */ -unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() -{ - return this->NumberOfPhysicalCPU; -} - -/** For Mac use sysctlbyname calls to find system info */ -bool SystemInformationImplementation::ParseSysCtl() -{ -#if defined(__APPLE__) - char retBuf[128]; - int err = 0; - uint64_t value = 0; - size_t len = sizeof(value); - sysctlbyname("hw.memsize", &value, &len, KWSYS_NULLPTR, 0); - this->TotalPhysicalMemory = static_cast(value / 1048576); - - // Parse values for Mac - this->AvailablePhysicalMemory = 0; - vm_statistics_data_t vmstat; - mach_msg_type_number_t count = HOST_VM_INFO_COUNT; - if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, - &count) == KERN_SUCCESS) { - len = sizeof(value); - err = sysctlbyname("hw.pagesize", &value, &len, KWSYS_NULLPTR, 0); - int64_t available_memory = vmstat.free_count * value; - this->AvailablePhysicalMemory = - static_cast(available_memory / 1048576); - } - -#ifdef VM_SWAPUSAGE - // Virtual memory. - int mib[2] = { CTL_VM, VM_SWAPUSAGE }; - size_t miblen = sizeof(mib) / sizeof(mib[0]); - struct xsw_usage swap; - len = sizeof(swap); - err = sysctl(mib, miblen, &swap, &len, KWSYS_NULLPTR, 0); - if (err == 0) { - this->AvailableVirtualMemory = - static_cast(swap.xsu_avail / 1048576); - this->TotalVirtualMemory = static_cast(swap.xsu_total / 1048576); - } -#else - this->AvailableVirtualMemory = 0; - this->TotalVirtualMemory = 0; -#endif - - // CPU Info - len = sizeof(this->NumberOfPhysicalCPU); - sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, - KWSYS_NULLPTR, 0); - len = sizeof(this->NumberOfLogicalCPU); - sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, KWSYS_NULLPTR, - 0); - - int cores_per_package = 0; - len = sizeof(cores_per_package); - err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len, - KWSYS_NULLPTR, 0); - // That name was not found, default to 1 - this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = - err != 0 ? 1 : static_cast(cores_per_package); - - len = sizeof(value); - sysctlbyname("hw.cpufrequency", &value, &len, KWSYS_NULLPTR, 0); - this->CPUSpeedInMHz = static_cast(value) / 1000000; - - // Chip family - len = sizeof(this->ChipID.Family); - // Seems only the intel chips will have this name so if this fails it is - // probably a PPC machine - err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, - KWSYS_NULLPTR, 0); - if (err != 0) // Go back to names we know but are less descriptive - { - this->ChipID.Family = 0; - ::memset(retBuf, 0, 128); - len = 32; - err = sysctlbyname("hw.machine", &retBuf, &len, KWSYS_NULLPTR, 0); - std::string machineBuf(retBuf); - if (machineBuf.find_first_of("Power") != std::string::npos) { - this->ChipID.Vendor = "IBM"; - len = sizeof(this->ChipID.Family); - err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, - KWSYS_NULLPTR, 0); - len = sizeof(this->ChipID.Model); - err = sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, - KWSYS_NULLPTR, 0); - this->FindManufacturer(); - } - } else // Should be an Intel Chip. - { - len = sizeof(this->ChipID.Family); - err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, - KWSYS_NULLPTR, 0); - - ::memset(retBuf, 0, 128); - len = 128; - err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, KWSYS_NULLPTR, 0); - // Chip Vendor - this->ChipID.Vendor = retBuf; - this->FindManufacturer(); - - // Chip Model - len = sizeof(value); - err = sysctlbyname("machdep.cpu.model", &value, &len, KWSYS_NULLPTR, 0); - this->ChipID.Model = static_cast(value); - - // Chip Stepping - len = sizeof(value); - value = 0; - err = sysctlbyname("machdep.cpu.stepping", &value, &len, KWSYS_NULLPTR, 0); - if (!err) { - this->ChipID.Revision = static_cast(value); - } - - // feature string - char* buf = KWSYS_NULLPTR; - size_t allocSize = 128; - - err = 0; - len = 0; - - // sysctlbyname() will return with err==0 && len==0 if the buffer is too - // small - while (err == 0 && len == 0) { - delete[] buf; - allocSize *= 2; - buf = new char[allocSize]; - if (!buf) { - break; - } - buf[0] = ' '; - len = allocSize - 2; // keep space for leading and trailing space - err = - sysctlbyname("machdep.cpu.features", buf + 1, &len, KWSYS_NULLPTR, 0); - } - if (!err && buf && len) { - // now we can match every flags as space + flag + space - buf[len + 1] = ' '; - std::string cpuflags(buf, len + 2); - - if ((cpuflags.find(" FPU ") != std::string::npos)) { - this->Features.HasFPU = true; - } - if ((cpuflags.find(" TSC ") != std::string::npos)) { - this->Features.HasTSC = true; - } - if ((cpuflags.find(" MMX ") != std::string::npos)) { - this->Features.HasMMX = true; - } - if ((cpuflags.find(" SSE ") != std::string::npos)) { - this->Features.HasSSE = true; - } - if ((cpuflags.find(" SSE2 ") != std::string::npos)) { - this->Features.HasSSE2 = true; - } - if ((cpuflags.find(" APIC ") != std::string::npos)) { - this->Features.HasAPIC = true; - } - if ((cpuflags.find(" CMOV ") != std::string::npos)) { - this->Features.HasCMOV = true; - } - if ((cpuflags.find(" MTRR ") != std::string::npos)) { - this->Features.HasMTRR = true; - } - if ((cpuflags.find(" ACPI ") != std::string::npos)) { - this->Features.HasACPI = true; - } - } - delete[] buf; - } - - // brand string - ::memset(retBuf, 0, sizeof(retBuf)); - len = sizeof(retBuf); - err = - sysctlbyname("machdep.cpu.brand_string", retBuf, &len, KWSYS_NULLPTR, 0); - if (!err) { - this->ChipID.ProcessorName = retBuf; - this->ChipID.ModelName = retBuf; - } - - // Cache size - len = sizeof(value); - err = sysctlbyname("hw.l1icachesize", &value, &len, KWSYS_NULLPTR, 0); - this->Features.L1CacheSize = static_cast(value); - len = sizeof(value); - err = sysctlbyname("hw.l2cachesize", &value, &len, KWSYS_NULLPTR, 0); - this->Features.L2CacheSize = static_cast(value); - - return true; -#else - return false; -#endif -} - -/** Extract a value from sysctl command */ -std::string SystemInformationImplementation::ExtractValueFromSysCtl( - const char* word) -{ - size_t pos = this->SysCtlBuffer.find(word); - if (pos != std::string::npos) { - pos = this->SysCtlBuffer.find(": ", pos); - size_t pos2 = this->SysCtlBuffer.find("\n", pos); - if (pos != std::string::npos && pos2 != std::string::npos) { - return this->SysCtlBuffer.substr(pos + 2, pos2 - pos - 2); - } - } - return ""; -} - -/** Run a given process */ -std::string SystemInformationImplementation::RunProcess( - std::vector args) -{ - std::string buffer = ""; - - // Run the application - kwsysProcess* gp = kwsysProcess_New(); - kwsysProcess_SetCommand(gp, &*args.begin()); - kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1); - - kwsysProcess_Execute(gp); - - char* data = KWSYS_NULLPTR; - int length; - double timeout = 255; - int pipe; // pipe id as returned by kwsysProcess_WaitForData() - - while ((static_cast( - pipe = kwsysProcess_WaitForData(gp, &data, &length, &timeout)), - (pipe == kwsysProcess_Pipe_STDOUT || - pipe == kwsysProcess_Pipe_STDERR))) // wait for 1s - { - buffer.append(data, length); - } - kwsysProcess_WaitForExit(gp, KWSYS_NULLPTR); - - int result = 0; - switch (kwsysProcess_GetState(gp)) { - case kwsysProcess_State_Exited: { - result = kwsysProcess_GetExitValue(gp); - } break; - case kwsysProcess_State_Error: { - std::cerr << "Error: Could not run " << args[0] << ":\n"; - std::cerr << kwsysProcess_GetErrorString(gp) << "\n"; - } break; - case kwsysProcess_State_Exception: { - std::cerr << "Error: " << args[0] << " terminated with an exception: " - << kwsysProcess_GetExceptionString(gp) << "\n"; - } break; - case kwsysProcess_State_Starting: - case kwsysProcess_State_Executing: - case kwsysProcess_State_Expired: - case kwsysProcess_State_Killed: { - // Should not get here. - std::cerr << "Unexpected ending state after running " << args[0] - << std::endl; - } break; - } - kwsysProcess_Delete(gp); - if (result) { - std::cerr << "Error " << args[0] << " returned :" << result << "\n"; - } - return buffer; -} - -std::string SystemInformationImplementation::ParseValueFromKStat( - const char* arguments) -{ - std::vector args; - args.clear(); - args.push_back("kstat"); - args.push_back("-p"); - - std::string command = arguments; - size_t start = std::string::npos; - size_t pos = command.find(' ', 0); - while (pos != std::string::npos) { - bool inQuotes = false; - // Check if we are between quotes - size_t b0 = command.find('"', 0); - size_t b1 = command.find('"', b0 + 1); - while (b0 != std::string::npos && b1 != std::string::npos && b1 > b0) { - if (pos > b0 && pos < b1) { - inQuotes = true; - break; - } - b0 = command.find('"', b1 + 1); - b1 = command.find('"', b0 + 1); - } - - if (!inQuotes) { - std::string arg = command.substr(start + 1, pos - start - 1); - - // Remove the quotes if any - size_t quotes = arg.find('"'); - while (quotes != std::string::npos) { - arg.erase(quotes, 1); - quotes = arg.find('"'); - } - args.push_back(arg.c_str()); - start = pos; - } - pos = command.find(' ', pos + 1); - } - std::string lastArg = command.substr(start + 1, command.size() - start - 1); - args.push_back(lastArg.c_str()); - - args.push_back(KWSYS_NULLPTR); - - std::string buffer = this->RunProcess(args); - - std::string value = ""; - for (size_t i = buffer.size() - 1; i > 0; i--) { - if (buffer[i] == ' ' || buffer[i] == '\t') { - break; - } - if (buffer[i] != '\n' && buffer[i] != '\r') { - std::string val = value; - value = buffer[i]; - value += val; - } - } - return value; -} - -/** Querying for system information from Solaris */ -bool SystemInformationImplementation::QuerySolarisMemory() -{ -#if defined(__SVR4) && defined(__sun) -// Solaris allows querying this value by sysconf, but if this is -// a 32 bit process on a 64 bit host the returned memory will be -// limited to 4GiB. So if this is a 32 bit process or if the sysconf -// method fails use the kstat interface. -#if SIZEOF_VOID_P == 8 - if (this->QueryMemoryBySysconf()) { - return true; - } -#endif - - char* tail; - unsigned long totalMemory = - strtoul(this->ParseValueFromKStat("-s physmem").c_str(), &tail, 0); - this->TotalPhysicalMemory = totalMemory / 128; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QuerySolarisProcessor() -{ - if (!this->QueryProcessorBySysconf()) { - return false; - } - - // Parse values - this->CPUSpeedInMHz = static_cast( - atoi(this->ParseValueFromKStat("-s clock_MHz").c_str())); - - // Chip family - this->ChipID.Family = 0; - - // Chip Model - this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type"); - this->ChipID.Model = 0; - - // Chip Vendor - if (this->ChipID.ProcessorName != "i386") { - this->ChipID.Vendor = "Sun"; - this->FindManufacturer(); - } - - return true; -} - -/** Querying for system information from Haiku OS */ -bool SystemInformationImplementation::QueryHaikuInfo() -{ -#if defined(__HAIKU__) - - // CPU count - system_info info; - get_system_info(&info); - this->NumberOfPhysicalCPU = info.cpu_count; - - // CPU speed - uint32 topologyNodeCount = 0; - cpu_topology_node_info* topology = 0; - get_cpu_topology_info(0, &topologyNodeCount); - if (topologyNodeCount != 0) - topology = new cpu_topology_node_info[topologyNodeCount]; - get_cpu_topology_info(topology, &topologyNodeCount); - - for (uint32 i = 0; i < topologyNodeCount; i++) { - if (topology[i].type == B_TOPOLOGY_CORE) { - this->CPUSpeedInMHz = - topology[i].data.core.default_frequency / 1000000.0f; - break; - } - } - - delete[] topology; - - // Physical Memory - this->TotalPhysicalMemory = (info.max_pages * B_PAGE_SIZE) / (1024 * 1024); - this->AvailablePhysicalMemory = this->TotalPhysicalMemory - - ((info.used_pages * B_PAGE_SIZE) / (1024 * 1024)); - - // NOTE: get_system_info_etc is currently a private call so just set to 0 - // until it becomes public - this->TotalVirtualMemory = 0; - this->AvailableVirtualMemory = 0; - - // Retrieve cpuid_info union for cpu 0 - cpuid_info cpu_info; - get_cpuid(&cpu_info, 0, 0); - - // Chip Vendor - // Use a temporary buffer so that we can add NULL termination to the string - char vbuf[13]; - strncpy(vbuf, cpu_info.eax_0.vendor_id, 12); - vbuf[12] = '\0'; - this->ChipID.Vendor = vbuf; - - this->FindManufacturer(); - - // Retrieve cpuid_info union for cpu 0 this time using a register value of 1 - get_cpuid(&cpu_info, 1, 0); - - this->NumberOfLogicalCPU = cpu_info.eax_1.logical_cpus; - - // Chip type - this->ChipID.Type = cpu_info.eax_1.type; - - // Chip family - this->ChipID.Family = cpu_info.eax_1.family; - - // Chip Model - this->ChipID.Model = cpu_info.eax_1.model; - - // Chip Revision - this->ChipID.Revision = cpu_info.eax_1.stepping; - - // Chip Extended Family - this->ChipID.ExtendedFamily = cpu_info.eax_1.extended_family; - - // Chip Extended Model - this->ChipID.ExtendedModel = cpu_info.eax_1.extended_model; - - // Get ChipID.ProcessorName from other information already gathered - this->RetrieveClassicalCPUIdentity(); - - // Cache size - this->Features.L1CacheSize = 0; - this->Features.L2CacheSize = 0; - - return true; - -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryQNXMemory() -{ -#if defined(__QNX__) - std::string buffer; - std::vector args; - args.clear(); - - args.push_back("showmem"); - args.push_back("-S"); - args.push_back(0); - buffer = this->RunProcess(args); - args.clear(); - - size_t pos = buffer.find("System RAM:"); - if (pos == std::string::npos) - return false; - pos = buffer.find(":", pos); - size_t pos2 = buffer.find("M (", pos); - if (pos2 == std::string::npos) - return false; - - pos++; - while (buffer[pos] == ' ') - pos++; - - this->TotalPhysicalMemory = atoi(buffer.substr(pos, pos2 - pos).c_str()); - return true; -#endif - return false; -} - -bool SystemInformationImplementation::QueryBSDMemory() -{ -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) - int ctrl[2] = { CTL_HW, HW_PHYSMEM }; -#if defined(HW_PHYSMEM64) - int64_t k; - ctrl[1] = HW_PHYSMEM64; -#else - int k; -#endif - size_t sz = sizeof(k); - - if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) { - return false; - } - - this->TotalPhysicalMemory = k >> 10 >> 10; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryQNXProcessor() -{ -#if defined(__QNX__) - // the output on my QNX 6.4.1 looks like this: - // Processor1: 686 Pentium II Stepping 3 2175MHz FPU - std::string buffer; - std::vector args; - args.clear(); - - args.push_back("pidin"); - args.push_back("info"); - args.push_back(0); - buffer = this->RunProcess(args); - args.clear(); - - size_t pos = buffer.find("Processor1:"); - if (pos == std::string::npos) - return false; - - size_t pos2 = buffer.find("MHz", pos); - if (pos2 == std::string::npos) - return false; - - size_t pos3 = pos2; - while (buffer[pos3] != ' ') - --pos3; - - this->CPUSpeedInMHz = atoi(buffer.substr(pos3 + 1, pos2 - pos3 - 1).c_str()); - - pos2 = buffer.find(" Stepping", pos); - if (pos2 != std::string::npos) { - pos2 = buffer.find(" ", pos2 + 1); - if (pos2 != std::string::npos && pos2 < pos3) { - this->ChipID.Revision = - atoi(buffer.substr(pos2 + 1, pos3 - pos2).c_str()); - } - } - - this->NumberOfPhysicalCPU = 0; - do { - pos = buffer.find("\nProcessor", pos + 1); - ++this->NumberOfPhysicalCPU; - } while (pos != std::string::npos); - this->NumberOfLogicalCPU = 1; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryBSDProcessor() -{ -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) - int k; - size_t sz = sizeof(k); - int ctrl[2] = { CTL_HW, HW_NCPU }; - - if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) { - return false; - } - - this->NumberOfPhysicalCPU = k; - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; - -#if defined(HW_CPUSPEED) - ctrl[1] = HW_CPUSPEED; - - if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) { - return false; - } - - this->CPUSpeedInMHz = (float)k; -#endif - -#if defined(CPU_SSE) - ctrl[0] = CTL_MACHDEP; - ctrl[1] = CPU_SSE; - - if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) { - return false; - } - - this->Features.HasSSE = (k > 0); -#endif - -#if defined(CPU_SSE2) - ctrl[0] = CTL_MACHDEP; - ctrl[1] = CPU_SSE2; - - if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0) { - return false; - } - - this->Features.HasSSE2 = (k > 0); -#endif - -#if defined(CPU_CPUVENDOR) - ctrl[0] = CTL_MACHDEP; - ctrl[1] = CPU_CPUVENDOR; - char vbuf[25]; - ::memset(vbuf, 0, sizeof(vbuf)); - sz = sizeof(vbuf) - 1; - if (sysctl(ctrl, 2, vbuf, &sz, NULL, 0) != 0) { - return false; - } - - this->ChipID.Vendor = vbuf; - this->FindManufacturer(); -#endif - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryHPUXMemory() -{ -#if defined(__hpux) - unsigned long tv = 0; - unsigned long tp = 0; - unsigned long av = 0; - unsigned long ap = 0; - struct pst_static pst; - struct pst_dynamic pdy; - - unsigned long ps = 0; - if (pstat_getstatic(&pst, sizeof(pst), (size_t)1, 0) == -1) { - return false; - } - - ps = pst.page_size; - tp = pst.physical_memory * ps; - tv = (pst.physical_memory + pst.pst_maxmem) * ps; - if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t)1, 0) == -1) { - return false; - } - - ap = tp - pdy.psd_rm * ps; - av = tv - pdy.psd_vm; - this->TotalVirtualMemory = tv >> 10 >> 10; - this->TotalPhysicalMemory = tp >> 10 >> 10; - this->AvailableVirtualMemory = av >> 10 >> 10; - this->AvailablePhysicalMemory = ap >> 10 >> 10; - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryHPUXProcessor() -{ -#if defined(__hpux) -#if defined(KWSYS_SYS_HAS_MPCTL_H) - int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0); - if (c <= 0) { - return false; - } - - this->NumberOfPhysicalCPU = c; - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; - - long t = sysconf(_SC_CPU_VERSION); - - if (t == -1) { - return false; - } - - switch (t) { - case CPU_PA_RISC1_0: - this->ChipID.Vendor = "Hewlett-Packard"; - this->ChipID.Family = 0x100; - break; - case CPU_PA_RISC1_1: - this->ChipID.Vendor = "Hewlett-Packard"; - this->ChipID.Family = 0x110; - break; - case CPU_PA_RISC2_0: - this->ChipID.Vendor = "Hewlett-Packard"; - this->ChipID.Family = 0x200; - break; -#if defined(CPU_HP_INTEL_EM_1_0) || defined(CPU_IA64_ARCHREV_0) -#ifdef CPU_HP_INTEL_EM_1_0 - case CPU_HP_INTEL_EM_1_0: -#endif -#ifdef CPU_IA64_ARCHREV_0 - case CPU_IA64_ARCHREV_0: -#endif - this->ChipID.Vendor = "GenuineIntel"; - this->Features.HasIA64 = true; - break; -#endif - default: - return false; - } - - this->FindManufacturer(); - - return true; -#else - return false; -#endif -#else - return false; -#endif -} - -/** Query the operating system information */ -bool SystemInformationImplementation::QueryOSInformation() -{ -#if defined(_WIN32) - - this->OSName = "Windows"; - - OSVERSIONINFOEXW osvi; - BOOL bIsWindows64Bit; - BOOL bOsVersionInfoEx; - char operatingSystem[256]; - - // Try calling GetVersionEx using the OSVERSIONINFOEX structure. - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXW)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -#pragma warning(push) -#ifdef __INTEL_COMPILER -#pragma warning(disable : 1478) -#else -#pragma warning(disable : 4996) -#endif -#endif - bOsVersionInfoEx = GetVersionExW((OSVERSIONINFOW*)&osvi); - if (!bOsVersionInfoEx) { - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); - if (!GetVersionExW((OSVERSIONINFOW*)&osvi)) { - return false; - } - } -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -#pragma warning(pop) -#endif - - switch (osvi.dwPlatformId) { - case VER_PLATFORM_WIN32_NT: - // Test for the product. - if (osvi.dwMajorVersion <= 4) { - this->OSRelease = "NT"; - } - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { - this->OSRelease = "2000"; - } - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - this->OSRelease = "XP"; - } - // XP Professional x64 - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { - this->OSRelease = "XP"; - } -#ifdef VER_NT_WORKSTATION - // Test for product type. - if (bOsVersionInfoEx) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) { - this->OSRelease = "Vista"; - } - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) { - this->OSRelease = "7"; - } -// VER_SUITE_PERSONAL may not be defined -#ifdef VER_SUITE_PERSONAL - else { - if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { - this->OSRelease += " Personal"; - } else { - this->OSRelease += " Professional"; - } - } -#endif - } else if (osvi.wProductType == VER_NT_SERVER) { - // Check for .NET Server instead of Windows XP. - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - this->OSRelease = ".NET"; - } - - // Continue with the type detection. - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { - this->OSRelease += " DataCenter Server"; - } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { - this->OSRelease += " Advanced Server"; - } else { - this->OSRelease += " Server"; - } - } - - sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); - this->OSVersion = operatingSystem; - } else -#endif // VER_NT_WORKSTATION - { - HKEY hKey; - wchar_t szProductType[80]; - DWORD dwBufLen; - - // Query the registry to retrieve information. - RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, - KEY_QUERY_VALUE, &hKey); - RegQueryValueExW(hKey, L"ProductType", NULL, NULL, - (LPBYTE)szProductType, &dwBufLen); - RegCloseKey(hKey); - - if (lstrcmpiW(L"WINNT", szProductType) == 0) { - this->OSRelease += " Professional"; - } - if (lstrcmpiW(L"LANMANNT", szProductType) == 0) { - // Decide between Windows 2000 Advanced Server and Windows .NET - // Enterprise Server. - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - this->OSRelease += " Standard Server"; - } else { - this->OSRelease += " Server"; - } - } - if (lstrcmpiW(L"SERVERNT", szProductType) == 0) { - // Decide between Windows 2000 Advanced Server and Windows .NET - // Enterprise Server. - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - this->OSRelease += " Enterprise Server"; - } else { - this->OSRelease += " Advanced Server"; - } - } - } - - // Display version, service pack (if any), and build number. - if (osvi.dwMajorVersion <= 4) { - // NB: NT 4.0 and earlier. - sprintf(operatingSystem, "version %ld.%ld %ls (Build %ld)", - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); - this->OSVersion = operatingSystem; - } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - // Windows XP and .NET server. - typedef BOOL(CALLBACK * LPFNPROC)(HANDLE, BOOL*); - HINSTANCE hKernelDLL; - LPFNPROC DLLProc; - - // Load the Kernel32 DLL. - hKernelDLL = LoadLibraryW(L"kernel32"); - if (hKernelDLL != NULL) { - // Only XP and .NET Server support IsWOW64Process so... Load - // dynamically! - DLLProc = (LPFNPROC)GetProcAddress(hKernelDLL, "IsWow64Process"); - - // If the function address is valid, call the function. - if (DLLProc != NULL) - (DLLProc)(GetCurrentProcess(), &bIsWindows64Bit); - else - bIsWindows64Bit = false; - - // Free the DLL module. - FreeLibrary(hKernelDLL); - } - } else { - // Windows 2000 and everything else. - sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); - this->OSVersion = operatingSystem; - } - break; - - case VER_PLATFORM_WIN32_WINDOWS: - // Test for the product. - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { - this->OSRelease = "95"; - if (osvi.szCSDVersion[1] == 'C') { - this->OSRelease += "OSR 2.5"; - } else if (osvi.szCSDVersion[1] == 'B') { - this->OSRelease += "OSR 2"; - } - } - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { - this->OSRelease = "98"; - if (osvi.szCSDVersion[1] == 'A') { - this->OSRelease += "SE"; - } - } - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { - this->OSRelease = "Me"; - } - break; - - case VER_PLATFORM_WIN32s: - this->OSRelease = "Win32s"; - break; - - default: - this->OSRelease = "Unknown"; - break; - } - - // Get the hostname - WORD wVersionRequested; - WSADATA wsaData; - char name[255]; - wVersionRequested = MAKEWORD(2, 0); - - if (WSAStartup(wVersionRequested, &wsaData) == 0) { - gethostname(name, sizeof(name)); - WSACleanup(); - } - this->Hostname = name; - - const char* arch = getenv("PROCESSOR_ARCHITECTURE"); - const char* wow64 = getenv("PROCESSOR_ARCHITEW6432"); - if (arch) { - this->OSPlatform = arch; - } - - if (wow64) { - // the PROCESSOR_ARCHITEW6432 is only defined when running 32bit programs - // on 64bit OS - this->OSIs64Bit = true; - } else if (arch) { - // all values other than x86 map to 64bit architectures - this->OSIs64Bit = (strncmp(arch, "x86", 3) != 0); - } - -#else - - struct utsname unameInfo; - int errorFlag = uname(&unameInfo); - if (errorFlag == 0) { - this->OSName = unameInfo.sysname; - this->Hostname = unameInfo.nodename; - this->OSRelease = unameInfo.release; - this->OSVersion = unameInfo.version; - this->OSPlatform = unameInfo.machine; - - // This is still insufficient to capture 64bit architecture such - // powerpc and possible mips and sparc - if (this->OSPlatform.find_first_of("64") != std::string::npos) { - this->OSIs64Bit = true; - } - } - -#ifdef __APPLE__ - this->OSName = "Unknown Apple OS"; - this->OSRelease = "Unknown product version"; - this->OSVersion = "Unknown build version"; - - this->CallSwVers("-productName", this->OSName); - this->CallSwVers("-productVersion", this->OSRelease); - this->CallSwVers("-buildVersion", this->OSVersion); -#endif - -#endif - - return true; -} - -int SystemInformationImplementation::CallSwVers(const char* arg, - std::string& ver) -{ -#ifdef __APPLE__ - std::vector args; - args.push_back("sw_vers"); - args.push_back(arg); - args.push_back(KWSYS_NULLPTR); - ver = this->RunProcess(args); - this->TrimNewline(ver); -#else - // avoid C4100 - (void)arg; - (void)ver; -#endif - return 0; -} - -void SystemInformationImplementation::TrimNewline(std::string& output) -{ - // remove \r - std::string::size_type pos = 0; - while ((pos = output.find("\r", pos)) != std::string::npos) { - output.erase(pos); - } - - // remove \n - pos = 0; - while ((pos = output.find("\n", pos)) != std::string::npos) { - output.erase(pos); - } -} - -/** Return true if the machine is 64 bits */ -bool SystemInformationImplementation::Is64Bits() -{ - return this->OSIs64Bit; -} -} diff --git a/thirdparty/KWSys/adios2sys/SystemInformation.hxx.in b/thirdparty/KWSys/adios2sys/SystemInformation.hxx.in deleted file mode 100644 index fe7e8b557a..0000000000 --- a/thirdparty/KWSys/adios2sys/SystemInformation.hxx.in +++ /dev/null @@ -1,167 +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 /* size_t */ -#include - -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(); - - 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 = NULL, - const char* procLimitEnvVarName = NULL); - - // Retrieve amount of physical memory installed on the system in KiB - // units. - LongLong GetHostMemoryTotal(); - - // Get total system RAM in units of KiB available colectivley to all - // processes in a process group. An example of a process group - // are the processes comprising an mpi program which is running in - // parallel. The amount of memory reported may differ from the host - // total if a host wide resource limit is applied. Such reource limits - // are reported to us via an application specified environment variable. - LongLong GetHostMemoryAvailable(const char* hostLimitEnvVarName = NULL); - - // Get total system RAM in units of KiB available to this process. - // This may differ from the host available if a per-process resource - // limit is applied. per-process memory limits are applied on unix - // system via rlimit API. Resource limits that are not imposed via - // rlimit API may be reported to us via an application specified - // environment variable. - LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName = NULL, - const char* procLimitEnvVarName = NULL); - - // Get the system RAM used by all processes on the host, in units of KiB. - LongLong GetHostMemoryUsed(); - - // Get system RAM used by this process id in units of KiB. - LongLong GetProcMemoryUsed(); - - // Return the load average of the machine or -0.0 if it cannot - // be determined. - double GetLoadAverage(); - - // enable/disable stack trace signal handler. In order to - // produce an informative stack trace the application should - // be dynamically linked and compiled with debug symbols. - static void SetStackTraceOnError(int enable); - - // format and return the current program stack in a string. In - // order to produce an informative stack trace the application - // should be dynamically linked and compiled with debug symbols. - static std::string GetProgramStack(int firstFrame, int wholePath); - - /** Run the different checks */ - void RunCPUCheck(); - void RunOSCheck(); - void RunMemoryCheck(); -}; - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/SystemTools.cxx b/thirdparty/KWSys/adios2sys/SystemTools.cxx deleted file mode 100644 index c6c01f8c4e..0000000000 --- a/thirdparty/KWSys/adios2sys/SystemTools.cxx +++ /dev/null @@ -1,4724 +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 -#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 -#include -#include -#include -#include - -// 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 -#include -#ifdef __QNX__ -#include /* for malloc/free on QNX */ -#endif -#include -#include -#include -#include - -#if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__) -#include /* for strcasecmp */ -#endif - -#ifdef _MSC_VER -#define umask _umask // Note this is still umask on Borland -#endif - -// support for realpath call -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#include -#ifndef __VMS -#include -#include -#endif -#include /* sigprocmask */ -#endif - -// Windows API. -#if defined(_WIN32) -#include -#include -#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 -#undef _WIN32 -#endif - -#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H -extern char** environ; -#endif - -#ifdef __CYGWIN__ -#include -#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 -#else -#include -#endif - -// This is a hack to prevent warnings about these functions being -// declared but not referenced. -#if defined(__sgi) && !defined(__GNUC__) -#include -namespace KWSYS_NAMESPACE { -class SystemToolsHack -{ -public: - enum - { - Ref1 = sizeof(cfgetospeed(0)), - Ref2 = sizeof(cfgetispeed(0)), - Ref3 = sizeof(tcgetattr(0, 0)), - Ref4 = sizeof(tcsetattr(0, 0, 0)), - Ref5 = sizeof(cfsetospeed(0, 0)), - Ref6 = sizeof(cfsetispeed(0, 0)) - }; -}; -} -#endif - -#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) || \ - defined(__BORLANDC__) || defined(__MINGW32__)) -#include -#include -#define _unlink unlink -#endif - -/* The maximum length of a file name. */ -#if defined(PATH_MAX) -#define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX -#elif defined(MAXPATHLEN) -#define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN -#else -#define KWSYS_SYSTEMTOOLS_MAXPATH 16384 -#endif -#if defined(__WATCOMC__) -#include -#define _mkdir mkdir -#define _rmdir rmdir -#define _getcwd getcwd -#define _chdir chdir -#endif - -#if defined(__BEOS__) && !defined(__ZETA__) -#include -#include - -// BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. -static inline void usleep(unsigned int msec) -{ - ::snooze(msec); -} - -// BeOS 5 also doesn't have realpath(), but its C++ API offers something close. -static inline char* realpath(const char* path, char* resolved_path) -{ - const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH; - snprintf(resolved_path, maxlen, "%s", path); - BPath normalized(resolved_path, NULL, true); - const char* resolved = normalized.Path(); - if (resolved != NULL) // NULL == No such file. - { - if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) { - return resolved_path; - } - } - return NULL; // something went wrong. -} -#endif - -#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 - -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 w_buf(len); - if (_wgetcwd(&w_buf[0], len)) { - size_t nlen = kwsysEncoding_wcstombs(buf, &w_buf[0], len); - if (nlen == static_cast(-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 = NULL; - DWORD size = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&message, 0, NULL); - *errorMessage = std::string(message, size); - LocalFree(message); - } else { - *errorMessage = "Unknown error."; - } - - resolved_path = ""; - } else { - resolved_path = path; - } -} -#else -#include - -#include -#include -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 = KWSYS_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, KWSYS_NULLPTR); - return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec); -#endif -} - -class SystemToolsTranslationMap : public std::map -{ -}; - -/* Type of character storing the environment. */ -#if defined(_WIN32) -typedef wchar_t envchar; -#else -typedef char envchar; -#endif - -/* Order by environment key only (VAR from VAR=VALUE). */ -struct kwsysEnvCompare -{ - bool operator()(const envchar* l, const envchar* r) const - { -#if defined(_WIN32) - const wchar_t* leq = wcschr(l, L'='); - const wchar_t* req = wcschr(r, L'='); - size_t llen = leq ? (leq - l) : wcslen(l); - size_t rlen = req ? (req - r) : wcslen(r); - if (llen == rlen) { - return wcsncmp(l, r, llen) < 0; - } else { - return wcscmp(l, r) < 0; - } -#else - const char* leq = strchr(l, '='); - const char* req = strchr(r, '='); - size_t llen = leq ? (leq - l) : strlen(l); - size_t rlen = req ? (req - r) : strlen(r); - if (llen == rlen) { - return strncmp(l, r, llen) < 0; - } else { - return strcmp(l, r) < 0; - } -#endif - } -}; - -class kwsysEnvSet : public std::set -{ -public: - class Free - { - const envchar* Env; - - public: - Free(const envchar* env) - : Env(env) - { - } - ~Free() { free(const_cast(this->Env)); } - }; - - const envchar* Release(const envchar* env) - { - const envchar* old = KWSYS_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 - } -}; - -class SystemToolsPathCaseMap - : public std::map -{ -}; - -class SystemToolsEnvMap : public std::map -{ -}; -#endif - -// adds the elements of the env variable path to the arg passed in -void SystemTools::GetPath(std::vector& path, const char* env) -{ - size_t const old_size = path.size(); -#if defined(_WIN32) && !defined(__CYGWIN__) - const char pathSep = ';'; -#else - const char pathSep = ':'; -#endif - if (!env) { - env = "PATH"; - } - std::string pathEnv; - if (!SystemTools::GetEnv(env, pathEnv)) { - return; - } - - // A hack to make the below algorithm work. - if (!pathEnv.empty() && *pathEnv.rbegin() != pathSep) { - pathEnv += pathSep; - } - std::string::size_type start = 0; - bool done = false; - while (!done) { - std::string::size_type endpos = pathEnv.find(pathSep, start); - if (endpos != std::string::npos) { - path.push_back(pathEnv.substr(start, endpos - start)); - start = endpos + 1; - } else { - done = true; - } - } - for (std::vector::iterator i = path.begin() + old_size; - i != path.end(); ++i) { - SystemTools::ConvertToUnixSlashes(*i); - } -} - -const char* SystemTools::GetEnvImpl(const char* key) -{ - const char* v = KWSYS_NULLPTR; -#if defined(_WIN32) - std::string env; - if (SystemTools::GetEnv(key, env)) { - std::string& menv = (*SystemTools::EnvMap)[key]; - menv = env; - v = menv.c_str(); - } -#else - v = getenv(key); -#endif - return v; -} - -const char* SystemTools::GetEnv(const char* key) -{ - return SystemTools::GetEnvImpl(key); -} - -const char* SystemTools::GetEnv(const std::string& key) -{ - return SystemTools::GetEnvImpl(key.c_str()); -} - -bool SystemTools::GetEnv(const char* key, std::string& result) -{ -#if defined(_WIN32) - const std::wstring wkey = Encoding::ToWide(key); - const wchar_t* wv = _wgetenv(wkey.c_str()); - if (wv) { - result = Encoding::ToNarrow(wv); - return true; - } -#else - const char* v = getenv(key); - if (v) { - result = v; - return true; - } -#endif - return false; -} - -bool SystemTools::GetEnv(const std::string& key, std::string& result) -{ - return SystemTools::GetEnv(key.c_str(), result); -} - -bool SystemTools::HasEnv(const char* key) -{ -#if defined(_WIN32) - const std::wstring wkey = Encoding::ToWide(key); - const wchar_t* v = _wgetenv(wkey.c_str()); -#else - const char* v = getenv(key); -#endif - return v != KWSYS_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.c_str()); -#else - kwsysUnPutEnv(*i); -#endif - free(const_cast(*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 != KWSYS_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 != KWSYS_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; - } - - SystemTools::ReplaceString(source, replace.c_str(), replace.size(), with); -} - -void SystemTools::ReplaceString(std::string& source, const char* replace, - const char* with) -{ - // do while hangs if replaceSize is 0 - if (!*replace) { - return; - } - - SystemTools::ReplaceString(source, replace, strlen(replace), - with ? with : ""); -} - -void SystemTools::ReplaceString(std::string& source, const char* replace, - size_t replaceSize, const std::string& with) -{ - const char* src = source.c_str(); - char* searchPos = const_cast(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 == NULL) { - return mode; - } - - if (view == SystemTools::KeyWOW64_32) { - return mode | KWSYS_ST_KEY_WOW64_32KEY; - } else if (view == SystemTools::KeyWOW64_64) { - return mode | KWSYS_ST_KEY_WOW64_64KEY; - } - return mode; -} -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::GetRegistrySubKeys(const std::string& key, - std::vector& 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&, KeyWOW64) -{ - return false; -} -#endif - -// Read a registry value. -// Example : -// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath -// => will return the data of the "default" value of the key -// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root -// => will return the data of the "Root" value of the key - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value, - KeyWOW64 view) -{ - bool valueset = false; - HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; - std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { - return false; - } - - HKEY hKey; - if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, - SystemToolsMakeRegistryMode(KEY_READ, view), - &hKey) != ERROR_SUCCESS) { - return false; - } else { - DWORD dwType, dwSize; - dwSize = 1023; - wchar_t data[1024]; - if (RegQueryValueExW(hKey, Encoding::ToWide(valuename).c_str(), NULL, - &dwType, (BYTE*)data, &dwSize) == ERROR_SUCCESS) { - if (dwType == REG_SZ) { - value = Encoding::ToNarrow(data); - valueset = true; - } else if (dwType == REG_EXPAND_SZ) { - wchar_t expanded[1024]; - DWORD dwExpandedSize = sizeof(expanded) / sizeof(expanded[0]); - if (ExpandEnvironmentStringsW(data, expanded, dwExpandedSize)) { - value = Encoding::ToNarrow(expanded); - valueset = true; - } - } - } - - RegCloseKey(hKey); - } - - return valueset; -} -#else -bool SystemTools::ReadRegistryValue(const std::string&, std::string&, KeyWOW64) -{ - return false; -} -#endif - -// Write a registry value. -// Example : -// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath -// => will set the data of the "default" value of the key -// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root -// => will set the data of the "Root" value of the key - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::WriteRegistryValue(const std::string& key, - const std::string& value, KeyWOW64 view) -{ - HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; - std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { - return false; - } - - HKEY hKey; - DWORD dwDummy; - wchar_t lpClass[] = L""; - if (RegCreateKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, lpClass, - REG_OPTION_NON_VOLATILE, - SystemToolsMakeRegistryMode(KEY_WRITE, view), NULL, - &hKey, &dwDummy) != ERROR_SUCCESS) { - return false; - } - - std::wstring wvalue = Encoding::ToWide(value); - if (RegSetValueExW(hKey, Encoding::ToWide(valuename).c_str(), 0, REG_SZ, - (CONST BYTE*)wvalue.c_str(), - (DWORD)(sizeof(wchar_t) * (wvalue.size() + 1))) == - ERROR_SUCCESS) { - return true; - } - return false; -} -#else -bool SystemTools::WriteRegistryValue(const std::string&, const std::string&, - KeyWOW64) -{ - return false; -} -#endif - -// Delete a registry value. -// Example : -// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath -// => will delete the data of the "default" value of the key -// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root -// => will delete the data of the "Root" value of the key - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view) -{ - HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; - std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { - return false; - } - - HKEY hKey; - if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, - SystemToolsMakeRegistryMode(KEY_WRITE, view), - &hKey) != ERROR_SUCCESS) { - return false; - } else { - if (RegDeleteValue(hKey, (LPTSTR)valuename.c_str()) == ERROR_SUCCESS) { - RegCloseKey(hKey); - return true; - } - } - return false; -} -#else -bool SystemTools::DeleteRegistryValue(const std::string&, KeyWOW64) -{ - return false; -} -#endif - -bool SystemTools::SameFile(const std::string& file1, const std::string& file2) -{ -#ifdef _WIN32 - HANDLE hFile1, hFile2; - - hFile1 = - CreateFileW(Encoding::ToWide(file1).c_str(), GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - hFile2 = - CreateFileW(Encoding::ToWide(file2).c_str(), GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (hFile1 == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE) { - if (hFile1 != INVALID_HANDLE_VALUE) { - CloseHandle(hFile1); - } - if (hFile2 != INVALID_HANDLE_VALUE) { - CloseHandle(hFile2); - } - return false; - } - - BY_HANDLE_FILE_INFORMATION fiBuf1; - BY_HANDLE_FILE_INFORMATION fiBuf2; - GetFileInformationByHandle(hFile1, &fiBuf1); - GetFileInformationByHandle(hFile2, &fiBuf2); - CloseHandle(hFile1); - CloseHandle(hFile2); - return (fiBuf1.dwVolumeSerialNumber == fiBuf2.dwVolumeSerialNumber && - fiBuf1.nFileIndexHigh == fiBuf2.nFileIndexHigh && - fiBuf1.nFileIndexLow == fiBuf2.nFileIndexLow); -#else - struct stat fileStat1, fileStat2; - if (stat(file1.c_str(), &fileStat1) == 0 && - stat(file2.c_str(), &fileStat2) == 0) { - // see if the files are the same file - // check the device inode and size - if (memcmp(&fileStat2.st_dev, &fileStat1.st_dev, - sizeof(fileStat1.st_dev)) == 0 && - memcmp(&fileStat2.st_ino, &fileStat1.st_ino, - sizeof(fileStat1.st_ino)) == 0 && - fileStat2.st_size == fileStat1.st_size) { - return true; - } - } - return false; -#endif -} - -bool SystemTools::PathExists(const std::string& path) -{ - if (path.empty()) { - return false; - } -#if defined(__CYGWIN__) - // Convert path to native windows path if possible. - char winpath[MAX_PATH]; - if (SystemTools::PathCygwinToWin32(path.c_str(), winpath)) { - return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); - } - struct stat st; - return lstat(path.c_str(), &st) == 0; -#elif defined(_WIN32) - return (GetFileAttributesW(Encoding::ToWindowsExtendedPath(path).c_str()) != - INVALID_FILE_ATTRIBUTES); -#else - struct stat st; - return lstat(path.c_str(), &st) == 0; -#endif -} - -bool SystemTools::FileExists(const char* filename) -{ - if (!filename) { - return false; - } - return SystemTools::FileExists(std::string(filename)); -} - -bool SystemTools::FileExists(const std::string& filename) -{ - if (filename.empty()) { - return false; - } -#if defined(__CYGWIN__) - // Convert filename to native windows path if possible. - char winpath[MAX_PATH]; - if (SystemTools::PathCygwinToWin32(filename.c_str(), winpath)) { - return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); - } - return access(filename.c_str(), R_OK) == 0; -#elif defined(_WIN32) - return ( - GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str()) != - INVALID_FILE_ATTRIBUTES); -#else -// SCO OpenServer 5.0.7/3.2's command has 711 permission. -#if defined(_SCO_DS) - return access(filename.c_str(), F_OK) == 0; -#else - return access(filename.c_str(), R_OK) == 0; -#endif -#endif -} - -bool SystemTools::FileExists(const char* filename, bool isFile) -{ - if (!filename) { - return false; - } - return SystemTools::FileExists(std::string(filename), isFile); -} - -bool SystemTools::FileExists(const std::string& filename, bool isFile) -{ - if (SystemTools::FileExists(filename)) { - // If isFile is set return not FileIsDirectory, - // so this will only be true if it is a file - return !isFile || !SystemTools::FileIsDirectory(filename); - } - return false; -} - -bool SystemTools::TestFileAccess(const char* filename, - TestFilePermissions permissions) -{ - if (!filename) { - return false; - } - return SystemTools::TestFileAccess(std::string(filename), permissions); -} - -bool SystemTools::TestFileAccess(const std::string& filename, - TestFilePermissions permissions) -{ - if (filename.empty()) { - return false; - } -#if defined(_WIN32) && !defined(__CYGWIN__) - // If execute set, change to read permission (all files on Windows - // are executable if they are readable). The CRT will always fail - // if you pass an execute bit. - if (permissions & TEST_FILE_EXECUTE) { - permissions &= ~TEST_FILE_EXECUTE; - permissions |= TEST_FILE_READ; - } - return _waccess(Encoding::ToWindowsExtendedPath(filename).c_str(), - permissions) == 0; -#else - return access(filename.c_str(), permissions) == 0; -#endif -} - -int SystemTools::Stat(const char* path, SystemTools::Stat_t* buf) -{ - if (!path) { - errno = EFAULT; - return -1; - } - return SystemTools::Stat(std::string(path), buf); -} - -int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf) -{ - if (path.empty()) { - errno = ENOENT; - return -1; - } -#if defined(_WIN32) && !defined(__CYGWIN__) - // Ideally we should use Encoding::ToWindowsExtendedPath to support - // long paths, but _wstat64 rejects paths with '?' in them, thinking - // they are wildcards. - std::wstring const& wpath = Encoding::ToWide(path); -#if defined(__BORLANDC__) - return _wstati64(wpath.c_str(), buf); -#else - return _wstat64(wpath.c_str(), buf); -#endif -#else - return stat(path.c_str(), buf); -#endif -} - -#ifdef __CYGWIN__ -bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path) -{ - SystemToolsTranslationMap::iterator i = - SystemTools::Cyg2Win32Map->find(path); - - if (i != SystemTools::Cyg2Win32Map->end()) { - strncpy(win32_path, i->second.c_str(), MAX_PATH); - } else { - if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) != - 0) { - win32_path[0] = 0; - } - SystemToolsTranslationMap::value_type entry(path, win32_path); - SystemTools::Cyg2Win32Map->insert(entry); - } - return win32_path[0] != 0; -} -#endif - -bool SystemTools::Touch(const std::string& filename, bool create) -{ - if (!SystemTools::PathExists(filename)) { - if (create) { - FILE* file = Fopen(filename, "a+b"); - if (file) { - fclose(file); - return true; - } - return false; - } else { - return true; - } - } -#if defined(_WIN32) && !defined(__CYGWIN__) - HANDLE h = CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), - FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); - if (!h) { - return false; - } - FILETIME mtime; - GetSystemTimeAsFileTime(&mtime); - if (!SetFileTime(h, 0, 0, &mtime)) { - CloseHandle(h); - return false; - } - CloseHandle(h); -#elif KWSYS_CXX_HAS_UTIMENSAT - struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, UTIME_NOW } }; - if (utimensat(AT_FDCWD, filename.c_str(), times, 0) < 0) { - return false; - } -#else - struct stat st; - if (stat(filename.c_str(), &st) < 0) { - return false; - } - struct timeval mtime; - gettimeofday(&mtime, 0); -#if KWSYS_CXX_HAS_UTIMES - struct timeval atime; -#if KWSYS_CXX_STAT_HAS_ST_MTIM - atime.tv_sec = st.st_atim.tv_sec; - atime.tv_usec = st.st_atim.tv_nsec / 1000; -#elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC - atime.tv_sec = st.st_atimespec.tv_sec; - atime.tv_usec = st.st_atimespec.tv_nsec / 1000; -#else - atime.tv_sec = st.st_atime; - atime.tv_usec = 0; -#endif - struct timeval times[2] = { atime, mtime }; - if (utimes(filename.c_str(), times) < 0) { - return false; - } -#else - struct utimbuf times = { st.st_atime, mtime.tv_sec }; - if (utime(filename.c_str(), ×) < 0) { - return false; - } -#endif -#endif - return true; -} - -bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2, - int* result) -{ - // Default to same time. - *result = 0; -#if !defined(_WIN32) || defined(__CYGWIN__) - // POSIX version. Use stat function to get file modification time. - struct stat s1; - if (stat(f1.c_str(), &s1) != 0) { - return false; - } - struct stat s2; - if (stat(f2.c_str(), &s2) != 0) { - return false; - } -#if KWSYS_CXX_STAT_HAS_ST_MTIM - // Compare using nanosecond resolution. - if (s1.st_mtim.tv_sec < s2.st_mtim.tv_sec) { - *result = -1; - } else if (s1.st_mtim.tv_sec > s2.st_mtim.tv_sec) { - *result = 1; - } else if (s1.st_mtim.tv_nsec < s2.st_mtim.tv_nsec) { - *result = -1; - } else if (s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec) { - *result = 1; - } -#elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC - // Compare using nanosecond resolution. - if (s1.st_mtimespec.tv_sec < s2.st_mtimespec.tv_sec) { - *result = -1; - } else if (s1.st_mtimespec.tv_sec > s2.st_mtimespec.tv_sec) { - *result = 1; - } else if (s1.st_mtimespec.tv_nsec < s2.st_mtimespec.tv_nsec) { - *result = -1; - } else if (s1.st_mtimespec.tv_nsec > s2.st_mtimespec.tv_nsec) { - *result = 1; - } -#else - // Compare using 1 second resolution. - if (s1.st_mtime < s2.st_mtime) { - *result = -1; - } else if (s1.st_mtime > s2.st_mtime) { - *result = 1; - } -#endif -#else - // Windows version. Get the modification time from extended file attributes. - WIN32_FILE_ATTRIBUTE_DATA f1d; - WIN32_FILE_ATTRIBUTE_DATA f2d; - if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f1).c_str(), - GetFileExInfoStandard, &f1d)) { - return false; - } - if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f2).c_str(), - GetFileExInfoStandard, &f2d)) { - return false; - } - - // Compare the file times using resolution provided by system call. - *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime); -#endif - return true; -} - -// Return a capitalized string (i.e the first letter is uppercased, all other -// are lowercased) -std::string SystemTools::Capitalized(const std::string& s) -{ - std::string n; - if (s.empty()) { - return n; - } - n.resize(s.size()); - n[0] = static_cast(toupper(s[0])); - for (size_t i = 1; i < s.size(); i++) { - n[i] = static_cast(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(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(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 KWSYS_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 KWSYS_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(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(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 KWSYS_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 KWSYS_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 KWSYS_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 KWSYS_NULLPTR; -} - -// Duplicate string -char* SystemTools::DuplicateString(const char* str) -{ - if (str) { - char* newstr = new char[strlen(str) + 1]; - return strcpy(newstr, str); - } - return KWSYS_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 SystemTools::SplitString(const std::string& p, - char sep, bool isPath) -{ - std::string path = p; - std::vector 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(va_arg(ap, double)); - } break; - default: { - // Assume the argument contributes no more than 64 characters. - length += 64; - - // Eat the argument. - static_cast(va_arg(ap, int)); - } break; - } - } - - // Move past the characters just tested. - ++cur; - } - } - - return static_cast(length); -} - -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.rbegin() == '/') { - // if it is c:/ then do not remove the trailing slash - if (!((size == 3 && pathCString[1] == ':'))) { - path.resize(size - 1); - } - } -} - -#ifdef _WIN32 -std::wstring SystemTools::ConvertToWindowsExtendedPath( - const std::string& source) -{ - return Encoding::ToWindowsExtendedPath(source); -} -#endif - -// change // to /, and escape any spaces in the path -std::string SystemTools::ConvertToUnixOutputPath(const std::string& path) -{ - std::string ret = path; - - // remove // except at the beginning might be a cygwin drive - std::string::size_type pos = 1; - while ((pos = ret.find("//", pos)) != std::string::npos) { - ret.erase(pos, 1); - } - // escape spaces and () in the path - if (ret.find_first_of(" ") != std::string::npos) { - std::string result = ""; - char lastch = 1; - for (const char* ch = ret.c_str(); *ch != '\0'; ++ch) { - // if it is already escaped then don't try to escape it again - if ((*ch == ' ') && lastch != '\\') { - result += '\\'; - } - result += *ch; - lastch = *ch; - } - ret = result; - } - return ret; -} - -std::string SystemTools::ConvertToOutputPath(const std::string& path) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - return SystemTools::ConvertToWindowsOutputPath(path); -#else - return SystemTools::ConvertToUnixOutputPath(path); -#endif -} - -// remove double slashes not at the start -std::string SystemTools::ConvertToWindowsOutputPath(const std::string& path) -{ - std::string ret; - // make it big enough for all of path and double quotes - ret.reserve(path.size() + 3); - // put path into the string - ret = path; - std::string::size_type pos = 0; - // first convert all of the slashes - while ((pos = ret.find('/', pos)) != std::string::npos) { - ret[pos] = '\\'; - pos++; - } - // check for really small paths - if (ret.size() < 2) { - return ret; - } - // now clean up a bit and remove double slashes - // Only if it is not the first position in the path which is a network - // path on windows - pos = 1; // start at position 1 - if (ret[0] == '\"') { - pos = 2; // if the string is already quoted then start at 2 - if (ret.size() < 3) { - return ret; - } - } - while ((pos = ret.find("\\\\", pos)) != std::string::npos) { - ret.erase(pos, 1); - } - // now double quote the path if it has spaces in it - // and is not already double quoted - if (ret.find(' ') != std::string::npos && ret[0] != '\"') { - ret.insert(static_cast(0), - static_cast(1), '\"'); - ret.append(1, '\"'); - } - return ret; -} - -bool SystemTools::CopyFileIfDifferent(const std::string& source, - const std::string& destination) -{ - // special check for a destination that is a directory - // FilesDiffer does not handle file to directory compare - if (SystemTools::FileIsDirectory(destination)) { - std::string new_destination = destination; - SystemTools::ConvertToUnixSlashes(new_destination); - new_destination += '/'; - std::string source_name = source; - new_destination += SystemTools::GetFilenameName(source_name); - if (SystemTools::FilesDiffer(source, new_destination)) { - return SystemTools::CopyFileAlways(source, destination); - } else { - // the files are the same so the copy is done return - // true - return true; - } - } - // source and destination are files so do a copy if they - // are different - if (SystemTools::FilesDiffer(source, destination)) { - return SystemTools::CopyFileAlways(source, destination); - } - // at this point the files must be the same so return true - return true; -} - -#define KWSYS_ST_BUFFER 4096 - -bool SystemTools::FilesDiffer(const std::string& source, - const std::string& destination) -{ - -#if defined(_WIN32) - WIN32_FILE_ATTRIBUTE_DATA statSource; - if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(source).c_str(), - GetFileExInfoStandard, &statSource) == 0) { - return true; - } - - WIN32_FILE_ATTRIBUTE_DATA statDestination; - if (GetFileAttributesExW( - Encoding::ToWindowsExtendedPath(destination).c_str(), - GetFileExInfoStandard, &statDestination) == 0) { - return true; - } - - if (statSource.nFileSizeHigh != statDestination.nFileSizeHigh || - statSource.nFileSizeLow != statDestination.nFileSizeLow) { - return true; - } - - if (statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0) { - return false; - } - off_t nleft = - ((__int64)statSource.nFileSizeHigh << 32) + statSource.nFileSizeLow; - -#else - - struct stat statSource; - if (stat(source.c_str(), &statSource) != 0) { - return true; - } - - struct stat statDestination; - if (stat(destination.c_str(), &statDestination) != 0) { - return true; - } - - if (statSource.st_size != statDestination.st_size) { - return true; - } - - if (statSource.st_size == 0) { - return false; - } - off_t nleft = statSource.st_size; -#endif - -#if defined(_WIN32) - kwsys::ifstream finSource(source.c_str(), (std::ios::binary | std::ios::in)); - kwsys::ifstream finDestination(destination.c_str(), - (std::ios::binary | std::ios::in)); -#else - kwsys::ifstream finSource(source.c_str()); - kwsys::ifstream finDestination(destination.c_str()); -#endif - if (!finSource || !finDestination) { - return true; - } - - // Compare the files a block at a time. - char source_buf[KWSYS_ST_BUFFER]; - char dest_buf[KWSYS_ST_BUFFER]; - while (nleft > 0) { - // Read a block from each file. - std::streamsize nnext = (nleft > KWSYS_ST_BUFFER) - ? KWSYS_ST_BUFFER - : static_cast(nleft); - finSource.read(source_buf, nnext); - finDestination.read(dest_buf, nnext); - - // If either failed to read assume they are different. - if (static_cast(finSource.gcount()) != nnext || - static_cast(finDestination.gcount()) != nnext) { - return true; - } - - // If this block differs the file differs. - if (memcmp(static_cast(source_buf), - static_cast(dest_buf), - static_cast(nnext)) != 0) { - return true; - } - - // Update the byte count remaining. - nleft -= nnext; - } - - // No differences found. - return false; -} - -/** - * Copy a file named by "source" to the file named by "destination". - */ -bool SystemTools::CopyFileAlways(const std::string& source, - const std::string& destination) -{ - // If files are the same do not copy - if (SystemTools::SameFile(source, destination)) { - return true; - } - mode_t perm = 0; - bool perms = SystemTools::GetPermissions(source, perm); - std::string real_destination = destination; - - if (SystemTools::FileIsDirectory(source)) { - SystemTools::MakeDirectory(destination); - } else { - const int bufferSize = 4096; - char buffer[bufferSize]; - - // If destination is a directory, try to create a file with the same - // name as the source in that directory. - - std::string destination_dir; - if (SystemTools::FileIsDirectory(destination)) { - destination_dir = real_destination; - SystemTools::ConvertToUnixSlashes(real_destination); - real_destination += '/'; - std::string source_name = source; - real_destination += SystemTools::GetFilenameName(source_name); - } else { - destination_dir = SystemTools::GetFilenamePath(destination); - } - - // Create destination directory - - SystemTools::MakeDirectory(destination_dir); - -// Open files -#if defined(_WIN32) - kwsys::ifstream fin( - Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)).c_str(), - std::ios::in | std::ios::binary); -#else - kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); -#endif - if (!fin) { - return false; - } - - // try and remove the destination file so that read only destination files - // can be written to. - // If the remove fails continue so that files in read only directories - // that do not allow file removal can be modified. - SystemTools::RemoveFile(real_destination); - -#if defined(_WIN32) - kwsys::ofstream fout( - Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(real_destination)) - .c_str(), - std::ios::out | std::ios::trunc | std::ios::binary); -#else - kwsys::ofstream fout(real_destination.c_str(), - std::ios::out | std::ios::trunc | std::ios::binary); -#endif - if (!fout) { - return false; - } - - // This copy loop is very sensitive on certain platforms with - // slightly broken stream libraries (like HPUX). Normally, it is - // incorrect to not check the error condition on the fin.read() - // before using the data, but the fin.gcount() will be zero if an - // error occurred. Therefore, the loop should be safe everywhere. - while (fin) { - fin.read(buffer, bufferSize); - if (fin.gcount()) { - fout.write(buffer, fin.gcount()); - } else { - break; - } - } - - // Make sure the operating system has finished writing the file - // before closing it. This will ensure the file is finished before - // the check below. - fout.flush(); - - fin.close(); - fout.close(); - - if (!fout) { - return false; - } - } - if (perms) { - if (!SystemTools::SetPermissions(real_destination, perm)) { - return false; - } - } - return true; -} - -bool SystemTools::CopyAFile(const std::string& source, - const std::string& destination, bool always) -{ - if (always) { - return SystemTools::CopyFileAlways(source, destination); - } else { - return SystemTools::CopyFileIfDifferent(source, destination); - } -} - -/** - * Copy a directory content from "source" directory to the directory named by - * "destination". - */ -bool SystemTools::CopyADirectory(const std::string& source, - const std::string& destination, bool always) -{ - Directory dir; - dir.Load(source); - size_t fileNum; - if (!SystemTools::MakeDirectory(destination)) { - return false; - } - for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { - if (strcmp(dir.GetFile(static_cast(fileNum)), ".") && - strcmp(dir.GetFile(static_cast(fileNum)), "..")) { - std::string fullPath = source; - fullPath += "/"; - fullPath += dir.GetFile(static_cast(fileNum)); - if (SystemTools::FileIsDirectory(fullPath)) { - std::string fullDestPath = destination; - fullDestPath += "/"; - fullDestPath += dir.GetFile(static_cast(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(fs.nFileSizeLow); - } -#else - struct stat fs; - if (stat(filename.c_str(), &fs) == 0) { - length = static_cast(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(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(fs.st_ctime) : 0; - } -#endif - return ct; -} - -std::string SystemTools::GetLastSystemError() -{ - int e = errno; - return strerror(e); -} - -#ifdef _WIN32 - -static bool IsJunction(const std::wstring& source) -{ -#ifdef FSCTL_GET_REPARSE_POINT - const DWORD JUNCTION_ATTRS = - FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT; - DWORD attrs = GetFileAttributesW(source.c_str()); - if (attrs == INVALID_FILE_ATTRIBUTES) { - return false; - } - if ((attrs & JUNCTION_ATTRS) != JUNCTION_ATTRS) { - return false; - } - - // Adjust privileges so that we can succefully open junction points. - HANDLE token; - TOKEN_PRIVILEGES privs; - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token); - LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &privs.Privileges[0].Luid); - privs.PrivilegeCount = 1; - privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, - NULL); - CloseHandle(token); - - HANDLE dir = CreateFileW( - source.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (dir == INVALID_HANDLE_VALUE) { - return false; - } - - // Query whether this is a reparse point or not. - BYTE buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - REPARSE_GUID_DATA_BUFFER* reparse_buffer = (REPARSE_GUID_DATA_BUFFER*)buffer; - DWORD sentinel; - - BOOL success = - DeviceIoControl(dir, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse_buffer, - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &sentinel, NULL); - - CloseHandle(dir); - - return (success && - (reparse_buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)); -#else - return false; -#endif -} - -static bool DeleteJunction(const std::wstring& source) -{ -#ifdef FSCTL_DELETE_REPARSE_POINT - // Adjust privileges so that we can succefully open junction points as - // read/write. - HANDLE token; - TOKEN_PRIVILEGES privs; - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token); - LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &privs.Privileges[0].Luid); - privs.PrivilegeCount = 1; - privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, - NULL); - CloseHandle(token); - - HANDLE dir = CreateFileW( - source.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (dir == INVALID_HANDLE_VALUE) { - return false; - } - - // Set up the structure so that we can delete the junction. - std::vector buffer(REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, 0); - REPARSE_GUID_DATA_BUFFER* reparse_buffer = - (REPARSE_GUID_DATA_BUFFER*)&buffer[0]; - DWORD sentinel; - - reparse_buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; - - BOOL success = DeviceIoControl( - dir, FSCTL_DELETE_REPARSE_POINT, reparse_buffer, - REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &sentinel, NULL); - - CloseHandle(dir); - - return !!success; -#else - return false; -#endif -} - -#endif - -bool SystemTools::RemoveFile(const std::string& source) -{ -#ifdef _WIN32 - std::wstring const& ws = Encoding::ToWindowsExtendedPath(source); - if (DeleteFileW(ws.c_str())) { - return true; - } - DWORD err = GetLastError(); - if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { - return true; - } - if (err != ERROR_ACCESS_DENIED) { - return false; - } - /* The file may be read-only. Try adding write permission. */ - mode_t mode; - if (!SystemTools::GetPermissions(source, mode) || - !SystemTools::SetPermissions(source, S_IWRITE)) { - SetLastError(err); - return false; - } - if (IsJunction(ws) && DeleteJunction(ws)) { - return true; - } - 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(fileNum)), ".") && - strcmp(dir.GetFile(static_cast(fileNum)), "..")) { - std::string fullPath = source; - fullPath += "/"; - fullPath += dir.GetFile(static_cast(fileNum)); - if (SystemTools::FileIsDirectory(fullPath) && - !SystemTools::FileIsSymlink(fullPath)) { - if (!SystemTools::RemoveADirectory(fullPath)) { - return false; - } - } else { - if (!SystemTools::RemoveFile(fullPath)) { - return false; - } - } - } - } - - return (Rmdir(source) == 0); -} - -/** - */ -size_t SystemTools::GetMaximumFilePathLength() -{ - return KWSYS_SYSTEMTOOLS_MAXPATH; -} - -/** - * Find the file the given name. Searches the given path and then - * the system search path. Returns the full path to the file if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindName(const std::string& name, - const std::vector& userPaths, - bool no_system_path) -{ - // Add the system search path to our path first - std::vector path; - if (!no_system_path) { - SystemTools::GetPath(path, "CMAKE_FILE_PATH"); - SystemTools::GetPath(path); - } - // now add the additional paths - { - for (std::vector::const_iterator i = userPaths.begin(); - i != userPaths.end(); ++i) { - path.push_back(*i); - } - } - // Add a trailing slash to all paths to aid the search process. - { - for (std::vector::iterator i = path.begin(); i != path.end(); - ++i) { - std::string& p = *i; - if (p.empty() || *p.rbegin() != '/') { - p += "/"; - } - } - } - // now look for the file - std::string tryPath; - for (std::vector::const_iterator p = path.begin(); - p != path.end(); ++p) { - tryPath = *p; - tryPath += name; - if (SystemTools::FileExists(tryPath)) { - return tryPath; - } - } - // Couldn't find the file. - return ""; -} - -/** - * Find the file the given name. Searches the given path and then - * the system search path. Returns the full path to the file if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindFile(const std::string& name, - const std::vector& userPaths, - bool no_system_path) -{ - std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path); - if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) { - return SystemTools::CollapseFullPath(tryPath); - } - // Couldn't find the file. - return ""; -} - -/** - * Find the directory the given name. Searches the given path and then - * the system search path. Returns the full path to the directory if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindDirectory( - const std::string& name, const std::vector& userPaths, - bool no_system_path) -{ - std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path); - if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) { - return SystemTools::CollapseFullPath(tryPath); - } - // Couldn't find the file. - return ""; -} - -/** - * Find the executable with the given name. Searches the given path and then - * the system search path. Returns the full path to the executable if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindProgram(const char* nameIn, - const std::vector& 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& userPaths, - bool no_system_path) -{ - std::string tryPath; - -#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) - std::vector extensions; - // check to see if the name already has a .xxx at - // the end of it - // on windows try .com then .exe - if (name.size() <= 3 || name[name.size() - 4] != '.') { - extensions.push_back(".com"); - extensions.push_back(".exe"); - - // first try with extensions if the os supports them - for (std::vector::iterator i = extensions.begin(); - i != extensions.end(); ++i) { - tryPath = name; - tryPath += *i; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - } - } -#endif - - // now try just the name - if (SystemTools::FileExists(name, true)) { - return SystemTools::CollapseFullPath(name); - } - // now construct the path - std::vector path; - // Add the system search path to our path. - if (!no_system_path) { - SystemTools::GetPath(path); - } - // now add the additional paths - { - for (std::vector::const_iterator i = userPaths.begin(); - i != userPaths.end(); ++i) { - path.push_back(*i); - } - } - // Add a trailing slash to all paths to aid the search process. - { - for (std::vector::iterator i = path.begin(); i != path.end(); - ++i) { - std::string& p = *i; - if (p.empty() || *p.rbegin() != '/') { - p += "/"; - } - } - } - // Try each path - for (std::vector::iterator p = path.begin(); p != path.end(); - ++p) { -#ifdef _WIN32 - // Remove double quotes from the path on windows - SystemTools::ReplaceString(*p, "\"", ""); -#endif -#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) - // first try with extensions - for (std::vector::iterator ext = extensions.begin(); - ext != extensions.end(); ++ext) { - tryPath = *p; - tryPath += name; - tryPath += *ext; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - } -#endif - // now try it without them - tryPath = *p; - tryPath += name; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - } - // Couldn't find the program. - return ""; -} - -std::string SystemTools::FindProgram(const std::vector& names, - const std::vector& path, - bool noSystemPath) -{ - for (std::vector::const_iterator it = names.begin(); - it != names.end(); ++it) { - // Try to find the program. - std::string result = SystemTools::FindProgram(*it, path, noSystemPath); - if (!result.empty()) { - return result; - } - } - return ""; -} - -/** - * Find the library with the given name. Searches the given path and then - * the system search path. Returns the full path to the library if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindLibrary(const std::string& name, - const std::vector& 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 path; - SystemTools::GetPath(path); - // now add the additional paths - { - for (std::vector::const_iterator i = userPaths.begin(); - i != userPaths.end(); ++i) { - path.push_back(*i); - } - } - // Add a trailing slash to all paths to aid the search process. - { - for (std::vector::iterator i = path.begin(); i != path.end(); - ++i) { - std::string& p = *i; - if (p.empty() || *p.rbegin() != '/') { - p += "/"; - } - } - } - std::string tryPath; - for (std::vector::const_iterator p = path.begin(); - p != path.end(); ++p) { -#if defined(__APPLE__) - tryPath = *p; - tryPath += name; - tryPath += ".framework"; - if (SystemTools::FileIsDirectory(tryPath)) { - return SystemTools::CollapseFullPath(tryPath); - } -#endif -#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) - tryPath = *p; - tryPath += name; - tryPath += ".lib"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } -#else - tryPath = *p; - tryPath += "lib"; - tryPath += name; - tryPath += ".so"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - tryPath = *p; - tryPath += "lib"; - tryPath += name; - tryPath += ".a"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - tryPath = *p; - tryPath += "lib"; - tryPath += name; - tryPath += ".sl"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - tryPath = *p; - tryPath += "lib"; - tryPath += name; - tryPath += ".dylib"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - tryPath = *p; - tryPath += "lib"; - tryPath += name; - tryPath += ".dll"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } -#endif - } - - // Couldn't find the library. - return ""; -} - -std::string SystemTools::GetRealPath(const std::string& path, - std::string* errorMessage) -{ - std::string ret; - Realpath(path, ret, errorMessage); - return ret; -} - -bool SystemTools::FileIsDirectory(const std::string& inName) -{ - if (inName.empty()) { - return false; - } - size_t length = inName.size(); - const char* name = inName.c_str(); - - // Remove any trailing slash from the name except in a root component. - char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH]; - std::string string_buffer; - size_t last = length - 1; - if (last > 0 && (name[last] == '/' || name[last] == '\\') && - strcmp(name, "/") != 0 && name[last - 1] != ':') { - if (last < sizeof(local_buffer)) { - memcpy(local_buffer, name, last); - local_buffer[last] = '\0'; - name = local_buffer; - } else { - string_buffer.append(name, last); - name = string_buffer.c_str(); - } - } - -// Now check the file node type. -#if defined(_WIN32) - DWORD attr = - GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str()); - if (attr != INVALID_FILE_ATTRIBUTES) { - return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; -#else - struct stat fs; - if (stat(name, &fs) == 0) { - return S_ISDIR(fs.st_mode); -#endif - } else { - return false; - } -} - -bool SystemTools::FileIsSymlink(const std::string& name) -{ -#if defined(_WIN32) - DWORD attr = - GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str()); - if (attr != INVALID_FILE_ATTRIBUTES) { - return (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0; - } else { - return false; - } -#else - struct stat fs; - if (lstat(name.c_str(), &fs) == 0) { - return S_ISLNK(fs.st_mode); - } else { - return false; - } -#endif -} - -bool SystemTools::FileIsFIFO(const std::string& name) -{ -#if defined(_WIN32) - HANDLE hFile = - CreateFileW(Encoding::ToWide(name).c_str(), GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return false; - } - const DWORD type = GetFileType(hFile); - CloseHandle(hFile); - return type == FILE_TYPE_PIPE; -#else - struct stat fs; - if (lstat(name.c_str(), &fs) == 0) { - return S_ISFIFO(fs.st_mode); - } else { - return false; - } -#endif -} - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::CreateSymlink(const std::string&, const std::string&) -{ - return false; -} -#else -bool SystemTools::CreateSymlink(const std::string& origName, - const std::string& newName) -{ - return symlink(origName.c_str(), newName.c_str()) >= 0; -} -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::ReadSymlink(const std::string&, std::string&) -{ - return false; -} -#else -bool SystemTools::ReadSymlink(const std::string& newName, - std::string& origName) -{ - char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1]; - int count = static_cast( - 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 failures; - std::string self = argv0 ? argv0 : ""; - failures.push_back(self); - SystemTools::ConvertToUnixSlashes(self); - self = SystemTools::FindProgram(self); - if (!SystemTools::FileExists(self)) { - if (buildDir) { - std::string intdir = "."; -#ifdef CMAKE_INTDIR - intdir = CMAKE_INTDIR; -#endif - self = buildDir; - self += "/bin/"; - self += intdir; - self += "/"; - self += exeName; - self += SystemTools::GetExecutableExtension(); - } - } - if (installPrefix) { - if (!SystemTools::FileExists(self)) { - failures.push_back(self); - self = installPrefix; - self += "/bin/"; - self += exeName; - } - } - if (!SystemTools::FileExists(self)) { - failures.push_back(self); - std::ostringstream msg; - msg << "Can not find the command line program "; - if (exeName) { - msg << exeName; - } - msg << "\n"; - if (argv0) { - msg << " argv[0] = \"" << argv0 << "\"\n"; - } - msg << " Attempted paths:\n"; - std::vector::iterator i; - for (i = failures.begin(); i != failures.end(); ++i) { - msg << " \"" << *i << "\"\n"; - } - errorMsg = msg.str(); - return false; - } - pathOut = self; - return true; -} - -std::string SystemTools::CollapseFullPath(const std::string& in_relative) -{ - return SystemTools::CollapseFullPath(in_relative, KWSYS_NULLPTR); -} - -void SystemTools::AddTranslationPath(const std::string& a, - const std::string& b) -{ - std::string path_a = a; - std::string path_b = b; - SystemTools::ConvertToUnixSlashes(path_a); - SystemTools::ConvertToUnixSlashes(path_b); - // First check this is a directory path, since we don't want the table to - // grow too fat - if (SystemTools::FileIsDirectory(path_a)) { - // Make sure the path is a full path and does not contain no '..' - // Ken--the following code is incorrect. .. can be in a valid path - // for example /home/martink/MyHubba...Hubba/Src - if (SystemTools::FileIsFullPath(path_b) && - path_b.find("..") == std::string::npos) { - // Before inserting make sure path ends with '/' - if (!path_a.empty() && *path_a.rbegin() != '/') { - path_a += '/'; - } - if (!path_b.empty() && *path_b.rbegin() != '/') { - path_b += '/'; - } - if (!(path_a == path_b)) { - SystemTools::TranslationMap->insert( - SystemToolsTranslationMap::value_type(path_a, path_b)); - } - } - } -} - -void SystemTools::AddKeepPath(const std::string& dir) -{ - std::string cdir; - Realpath(SystemTools::CollapseFullPath(dir).c_str(), cdir); - SystemTools::AddTranslationPath(cdir, dir); -} - -void SystemTools::CheckTranslationPath(std::string& path) -{ - // Do not translate paths that are too short to have meaningful - // translations. - if (path.size() < 2) { - return; - } - - // Always add a trailing slash before translation. It does not - // matter if this adds an extra slash, but we do not want to - // translate part of a directory (like the foo part of foo-dir). - path += "/"; - - // In case a file was specified we still have to go through this: - // Now convert any path found in the table back to the one desired: - std::map::const_iterator it; - for (it = SystemTools::TranslationMap->begin(); - it != SystemTools::TranslationMap->end(); ++it) { - // We need to check of the path is a substring of the other path - if (path.find(it->first) == 0) { - path = path.replace(0, it->first.size(), it->second); - } - } - - // Remove the trailing slash we added before. - path.erase(path.end() - 1, path.end()); -} - -static void SystemToolsAppendComponents( - std::vector& out_components, - std::vector::iterator first, - std::vector::iterator last) -{ - static const std::string up = ".."; - static const std::string cur = "."; - for (std::vector::const_iterator i = first; i != last; ++i) { - if (*i == up) { - if (out_components.size() > 1) { - out_components.resize(out_components.size() - 1); - } - } else if (!i->empty() && *i != cur) { -#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) - out_components.push_back(std::move(*i)); -#else - out_components.push_back(*i); -#endif - } - } -} - -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 out_components; - - // Split the input path components. - std::vector 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 base_components; - // Use the given base path. - SystemTools::SplitPath(in_base, base_components); - - // Append base path components to the output path. - out_components.push_back(base_components[0]); - SystemToolsAppendComponents(out_components, base_components.begin() + 1, - base_components.end()); - } - - // Append input path components to the output path. - SystemToolsAppendComponents(out_components, path_components.begin(), - path_components.end()); - - // Transform the path back to a string. - std::string newPath = SystemTools::JoinPath(out_components); - - // Update the translation table with this potentially new path. I am not - // sure why this line is here, it seems really questionable, but yet I - // would put good money that if I remove it something will break, basically - // from what I can see it created a mapping from the collapsed path, to be - // replaced by the input path, which almost completely does the opposite of - // this function, the only thing preventing this from happening a lot is - // that if the in_path has a .. in it, then it is not added to the - // translation table. So for most calls this either does nothing due to the - // .. or it adds a translation between identical paths as nothing was - // collapsed, so I am going to try to comment it out, and see what hits the - // fan, hopefully quickly. - // Commented out line below: - // SystemTools::AddTranslationPath(newPath, in_path); - - SystemTools::CheckTranslationPath(newPath); -#ifdef _WIN32 - newPath = SystemTools::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 localSplit = - SystemTools::SplitString(l, '/', true); - std::vector remoteSplit = - SystemTools::SplitString(r, '/', true); - std::vector - commonPath; // store shared parts of path in this array - std::vector finalPath; // store the final relative path here - // count up how many matching directory names there are from the start - unsigned int sameCount = 0; - while (((sameCount <= (localSplit.size() - 1)) && - (sameCount <= (remoteSplit.size() - 1))) && -// for Windows and Apple do a case insensitive string compare -#if defined(_WIN32) || defined(__APPLE__) - SystemTools::Strucmp(localSplit[sameCount].c_str(), - remoteSplit[sameCount].c_str()) == 0 -#else - localSplit[sameCount] == remoteSplit[sameCount] -#endif - ) { - // put the common parts of the path into the commonPath array - commonPath.push_back(localSplit[sameCount]); - // erase the common parts of the path from the original path arrays - localSplit[sameCount] = ""; - remoteSplit[sameCount] = ""; - sameCount++; - } - - // If there is nothing in common at all then just return the full - // path. This is the case only on windows when the paths have - // different drive letters. On unix two full paths always at least - // have the root "/" in common so we will return a relative path - // that passes through the root directory. - if (sameCount == 0) { - return remote; - } - - // for each entry that is not common in the local path - // add a ../ to the finalpath array, this gets us out of the local - // path into the remote dir - for (unsigned int i = 0; i < localSplit.size(); ++i) { - if (!localSplit[i].empty()) { - finalPath.push_back("../"); - } - } - // for each entry that is not common in the remote path add it - // to the final path. - for (std::vector::iterator vit = remoteSplit.begin(); - vit != remoteSplit.end(); ++vit) { - if (!vit->empty()) { - finalPath.push_back(*vit); - } - } - std::string relativePath; // result string - // now turn the array of directories into a unix path by puttint / - // between each entry that does not already have one - for (std::vector::iterator vit1 = finalPath.begin(); - vit1 != finalPath.end(); ++vit1) { - if (!relativePath.empty() && *relativePath.rbegin() != '/') { - relativePath += "/"; - } - relativePath += *vit1; - } - return relativePath; -} - -#ifdef _WIN32 -static std::string GetCasePathName(std::string const& pathIn) -{ - std::string casePath; - - // 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 path_components; - SystemTools::SplitPath(pathIn, path_components); - - // Start with root component. - std::vector::size_type idx = 0; - casePath = path_components[idx++]; - // make sure drive letter is always upper case - if (casePath.size() > 1 && casePath[1] == ':') { - casePath[0] = toupper(casePath[0]); - } - const char* sep = ""; - - // If network path, fill casePath with server/share so FindFirstFile - // will work after that. Maybe someday call other APIs to get - // actual case of servers and shares. - if (path_components.size() > 2 && path_components[0] == "//") { - casePath += path_components[idx++]; - casePath += "/"; - casePath += path_components[idx++]; - sep = "/"; - } - - // Convert case of all components that exist. - bool converting = true; - for (; idx < path_components.size(); idx++) { - casePath += sep; - sep = "/"; - - if (converting) { - // If path component contains wildcards, we skip matching - // because these filenames are not allowed on windows, - // and we do not want to match a different file. - if (path_components[idx].find('*') != std::string::npos || - path_components[idx].find('?') != std::string::npos) { - converting = false; - } else { - std::string test_str = casePath; - test_str += path_components[idx]; - WIN32_FIND_DATAW findData; - HANDLE hFind = - ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData); - if (INVALID_HANDLE_VALUE != hFind) { - path_components[idx] = Encoding::ToNarrow(findData.cFileName); - ::FindClose(hFind); - } else { - converting = false; - } - } - } - - casePath += path_components[idx]; - } - return casePath; -} -#endif - -std::string SystemTools::GetActualCaseForPath(const std::string& p) -{ -#ifndef _WIN32 - return p; -#else - return GetCasePathName(p); -#endif -} - -#ifdef _WIN32 -std::string SystemTools::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 - SystemToolsPathCaseMap::iterator i = SystemTools::PathCaseMap->find(p); - if (i != SystemTools::PathCaseMap->end()) { - return i->second; - } - std::string casePath = GetCasePathName(p); - if (casePath.size() > MAX_PATH) { - return casePath; - } - (*SystemTools::PathCaseMap)[p] = casePath; - return casePath; -} -#endif - -const char* SystemTools::SplitPathRootComponent(const std::string& p, - std::string* root) -{ - // Identify the root component. - const char* c = p.c_str(); - if ((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\')) { - // Network path. - if (root) { - *root = "//"; - } - c += 2; - } else if (c[0] == '/' || c[0] == '\\') { - // Unix path (or Windows path w/out drive letter). - if (root) { - *root = "/"; - } - c += 1; - } else if (c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\')) { - // Windows path. - if (root) { - (*root) = "_:/"; - (*root)[0] = c[0]; - } - c += 3; - } else if (c[0] && c[1] == ':') { - // Path relative to a windows drive working directory. - if (root) { - (*root) = "_:"; - (*root)[0] = c[0]; - } - c += 2; - } else if (c[0] == '~') { - // Home directory. The returned root should always have a - // trailing slash so that appending components as - // c[0]c[1]/c[2]/... works. The remaining path returned should - // skip the first slash if it exists: - // - // "~" : root = "~/" , return "" - // "~/ : root = "~/" , return "" - // "~/x : root = "~/" , return "x" - // "~u" : root = "~u/", return "" - // "~u/" : root = "~u/", return "" - // "~u/x" : root = "~u/", return "x" - size_t n = 1; - while (c[n] && c[n] != '/') { - ++n; - } - if (root) { - root->assign(c, n); - *root += '/'; - } - if (c[n] == '/') { - ++n; - } - c += n; - } else { - // Relative path. - if (root) { - *root = ""; - } - } - - // Return the remaining path. - return c; -} - -void SystemTools::SplitPath(const std::string& p, - std::vector& components, - bool expand_home_dir) -{ - const char* c; - components.clear(); - - // Identify the root component. - { - std::string root; - c = SystemTools::SplitPathRootComponent(p, &root); - - // Expand home directory references if requested. - if (expand_home_dir && !root.empty() && root[0] == '~') { - std::string homedir; - root = root.substr(0, root.size() - 1); - if (root.size() == 1) { -#if defined(_WIN32) && !defined(__CYGWIN__) - if (!SystemTools::GetEnv("USERPROFILE", homedir)) -#endif - SystemTools::GetEnv("HOME", homedir); - } -#ifdef HAVE_GETPWNAM - else if (passwd* pw = getpwnam(root.c_str() + 1)) { - if (pw->pw_dir) { - homedir = pw->pw_dir; - } - } -#endif - if (!homedir.empty() && - (*homedir.rbegin() == '/' || *homedir.rbegin() == '\\')) { - homedir.resize(homedir.size() - 1); - } - SystemTools::SplitPath(homedir, components); - } else { - components.push_back(root); - } - } - - // Parse the remaining components. - const char* first = c; - const char* last = first; - for (; *last; ++last) { - if (*last == '/' || *last == '\\') { - // End of a component. Save it. - components.push_back(std::string(first, last)); - first = last + 1; - } - } - - // Save the last component unless there were no components. - if (last != c) { - components.push_back(std::string(first, last)); - } -} - -std::string SystemTools::JoinPath(const std::vector& components) -{ - return SystemTools::JoinPath(components.begin(), components.end()); -} - -std::string SystemTools::JoinPath( - std::vector::const_iterator first, - std::vector::const_iterator last) -{ - // Construct result in a single string. - std::string result; - size_t len = 0; - std::vector::const_iterator i; - for (i = first; i != last; ++i) { - len += 1 + i->size(); - } - result.reserve(len); - - // The first two components do not add a slash. - if (first != last) { - result.append(*first++); - } - if (first != last) { - result.append(*first++); - } - - // All remaining components are always separated with a slash. - while (first != last) { - result.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& lines, char separator) -{ - std::string data(str); - std::string::size_type lpos = 0; - while (lpos < data.length()) { - std::string::size_type rpos = data.find_first_of(separator, lpos); - if (rpos == std::string::npos) { - // Line ends at end of string without a newline. - lines.push_back(data.substr(lpos)); - return false; - } else { - // Line ends in a "\n", remove the character. - lines.push_back(data.substr(lpos, rpos - lpos)); - } - lpos = rpos + 1; - } - return true; -} - -bool SystemTools::Split(const std::string& str, - std::vector& 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(read_length - text_count) / - static_cast(read_length)); - - if (current_percent_bin >= percent_bin) { - return SystemTools::FileTypeBinary; - } - - return SystemTools::FileTypeText; -} - -bool SystemTools::LocateFileInDir(const char* filename, const char* dir, - std::string& filename_found, - int try_filename_dirs) -{ - if (!filename || !dir) { - return false; - } - - // Get the basename of 'filename' - - std::string filename_base = SystemTools::GetFilenameName(filename); - - // Check if 'dir' is really a directory - // If win32 and matches something like C:, accept it as a dir - - std::string real_dir; - if (!SystemTools::FileIsDirectory(dir)) { -#if defined(_WIN32) - size_t dir_len = strlen(dir); - if (dir_len < 2 || dir[dir_len - 1] != ':') { -#endif - real_dir = SystemTools::GetFilenamePath(dir); - dir = real_dir.c_str(); -#if defined(_WIN32) - } -#endif - } - - // Try to find the file in 'dir' - - bool res = false; - if (!filename_base.empty() && dir) { - size_t dir_len = strlen(dir); - int need_slash = - (dir_len && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\'); - - std::string temp = dir; - if (need_slash) { - temp += "/"; - } - temp += filename_base; - - if (SystemTools::FileExists(temp)) { - res = true; - filename_found = temp; - } - - // If not found, we can try harder by appending part of the file to - // to the directory to look inside. - // Example: if we were looking for /foo/bar/yo.txt in /d1/d2, then - // try to find yo.txt in /d1/d2/bar, then /d1/d2/foo/bar, etc. - - else if (try_filename_dirs) { - std::string filename_dir(filename); - std::string filename_dir_base; - std::string filename_dir_bases; - do { - filename_dir = SystemTools::GetFilenamePath(filename_dir); - filename_dir_base = SystemTools::GetFilenameName(filename_dir); -#if defined(_WIN32) - if (filename_dir_base.empty() || *filename_dir_base.rbegin() == ':') -#else - if (filename_dir_base.empty()) -#endif - { - break; - } - - filename_dir_bases = filename_dir_base + "/" + filename_dir_bases; - - temp = dir; - if (need_slash) { - temp += "/"; - } - temp += filename_dir_bases; - - res = SystemTools::LocateFileInDir(filename_base.c_str(), temp.c_str(), - filename_found, 0); - - } while (!res && !filename_dir_base.empty()); - } - } - - return res; -} - -bool SystemTools::FileIsFullPath(const std::string& in_name) -{ - return SystemTools::FileIsFullPath(in_name.c_str(), in_name.size()); -} - -bool SystemTools::FileIsFullPath(const char* in_name) -{ - return SystemTools::FileIsFullPath(in_name, - in_name[0] ? (in_name[1] ? 2 : 1) : 0); -} - -bool SystemTools::FileIsFullPath(const char* in_name, size_t len) -{ -#if defined(_WIN32) || defined(__CYGWIN__) - // On Windows, the name must be at least two characters long. - if (len < 2) { - return false; - } - if (in_name[1] == ':') { - return true; - } - if (in_name[0] == '\\') { - return true; - } -#else - // On UNIX, the name must be at least one character long. - if (len < 1) { - return false; - } -#endif -#if !defined(_WIN32) - if (in_name[0] == '~') { - return true; - } -#endif - // On UNIX, the name must begin in a '/'. - // On Windows, if the name begins in a '/', then it is a full - // network path. - if (in_name[0] == '/') { - return true; - } - return false; -} - -bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - std::string tempPath = path; // create a buffer - - // if the path passed in has quotes around it, first remove the quotes - if (!path.empty() && path[0] == '"' && *path.rbegin() == '"') { - tempPath = path.substr(1, path.length() - 2); - } - - std::wstring wtempPath = Encoding::ToWide(tempPath); - DWORD ret = GetShortPathNameW(wtempPath.c_str(), NULL, 0); - std::vector buffer(ret); - if (ret != 0) { - ret = GetShortPathNameW(wtempPath.c_str(), &buffer[0], - static_cast(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; -} - -// Due to a buggy stream library on the HP and another on Mac OS X, we -// need this very carefully written version of getline. Returns true -// if any data were read before the end-of-file was reached. -bool SystemTools::GetLineFromStream(std::istream& is, std::string& line, - bool* has_newline /* = 0 */, - long sizeLimit /* = -1 */) -{ - const int bufferSize = 1024; - char buffer[bufferSize]; - bool haveData = false; - bool haveNewline = false; - - // Start with an empty line. - line = ""; - - long leftToRead = sizeLimit; - - // Early short circuit return if stream is no good. Just return - // false and the empty line. (Probably means caller tried to - // create a file stream with a non-existent file name...) - // - if (!is) { - if (has_newline) { - *has_newline = false; - } - return false; - } - - // If no characters are read from the stream, the end of file has - // been reached. Clear the fail bit just before reading. - while (!haveNewline && leftToRead != 0 && - (static_cast(is.clear(is.rdstate() & ~std::ios::failbit)), - static_cast(is.getline(buffer, bufferSize)), - is.gcount() > 0)) { - // We have read at least one byte. - haveData = true; - - // If newline character was read the gcount includes the character - // but the buffer does not: the end of line has been reached. - size_t length = strlen(buffer); - if (length < static_cast(is.gcount())) { - haveNewline = true; - } - - // Avoid storing a carriage return character. - if (length > 0 && buffer[length - 1] == '\r') { - buffer[length - 1] = 0; - } - - // if we read too much then truncate the buffer - if (leftToRead > 0) { - if (static_cast(length) > leftToRead) { - buffer[leftToRead] = 0; - leftToRead = 0; - } else { - leftToRead -= static_cast(length); - } - } - - // Append the data read to the line. - line.append(buffer); - } - - // Return the results. - if (has_newline) { - *has_newline = haveNewline; - } - return haveData; -} - -int SystemTools::GetTerminalWidth() -{ - int width = -1; -#ifdef HAVE_TTY_INFO - struct winsize ws; - 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(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.rbegin() == '/'; // 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) -#else -#pragma warning(disable : 4996) -#endif -#endif - bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA*)&osvi); - if (!bOsVersionInfoEx) { - return 0; - } -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -#pragma warning(pop) -#endif - - switch (osvi.dwPlatformId) { - // Test for the Windows NT product family. - - case VER_PLATFORM_WIN32_NT: - - // Test for the specific product family. - if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows 10"; - } else { - res += "Microsoft Windows Server 2016 family"; - } - } - - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows 8.1"; - } else { - res += "Microsoft Windows Server 2012 R2 family"; - } - } - - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows 8"; - } else { - res += "Microsoft Windows Server 2012 family"; - } - } - - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows 7"; - } else { - res += "Microsoft Windows Server 2008 R2 family"; - } - } - - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows Vista"; - } else { - res += "Microsoft Windows Server 2008 family"; - } - } - - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { - res += "Microsoft Windows Server 2003 family"; - } - - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - res += "Microsoft Windows XP"; - } - - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { - res += "Microsoft Windows 2000"; - } - - if (osvi.dwMajorVersion <= 4) { - res += "Microsoft Windows NT"; - } - - // Test for specific product on Windows NT 4.0 SP6 and later. - - if (bOsVersionInfoEx) { - // Test for the workstation type. - - if (osvi.wProductType == VER_NT_WORKSTATION) { - if (osvi.dwMajorVersion == 4) { - res += " Workstation 4.0"; - } else if (osvi.dwMajorVersion == 5) { - if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { - res += " Home Edition"; - } else { - res += " Professional"; - } - } - } - - // Test for the server type. - - else if (osvi.wProductType == VER_NT_SERVER) { - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { - res += " Datacenter Edition"; - } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { - res += " Enterprise Edition"; - } else if (osvi.wSuiteMask == VER_SUITE_BLADE) { - res += " Web Edition"; - } else { - res += " Standard Edition"; - } - } - - else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { - res += " Datacenter Server"; - } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { - res += " Advanced Server"; - } else { - res += " Server"; - } - } - - else if (osvi.dwMajorVersion <= 4) // Windows NT 4.0 - { - if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { - res += " Server 4.0, Enterprise Edition"; - } else { - res += " Server 4.0"; - } - } - } - } - - // Test for specific product on Windows NT 4.0 SP5 and earlier - - else { - HKEY hKey; -#define BUFSIZE 80 - wchar_t szProductType[BUFSIZE]; - DWORD dwBufLen = BUFSIZE; - LONG lRet; - - lRet = - RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", - 0, KEY_QUERY_VALUE, &hKey); - if (lRet != ERROR_SUCCESS) { - return 0; - } - - lRet = RegQueryValueExW(hKey, L"ProductType", NULL, NULL, - (LPBYTE)szProductType, &dwBufLen); - - if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE)) { - return 0; - } - - RegCloseKey(hKey); - - if (lstrcmpiW(L"WINNT", szProductType) == 0) { - res += " Workstation"; - } - if (lstrcmpiW(L"LANMANNT", szProductType) == 0) { - res += " Server"; - } - if (lstrcmpiW(L"SERVERNT", szProductType) == 0) { - res += " Advanced Server"; - } - - res += " "; - sprintf(buffer, "%ld", osvi.dwMajorVersion); - res += buffer; - res += "."; - sprintf(buffer, "%ld", osvi.dwMinorVersion); - res += buffer; - } - - // Display service pack (if any) and build number. - - if (osvi.dwMajorVersion == 4 && - lstrcmpiA(osvi.szCSDVersion, "Service Pack 6") == 0) { - HKEY hKey; - LONG lRet; - - // Test for SP6 versus SP6a. - - lRet = RegOpenKeyExW( - HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009", - 0, KEY_QUERY_VALUE, &hKey); - - if (lRet == ERROR_SUCCESS) { - res += " Service Pack 6a (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); - res += buffer; - res += ")"; - } else // Windows NT 4.0 prior to SP6a - { - res += " "; - res += osvi.szCSDVersion; - res += " (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); - res += buffer; - res += ")"; - } - - RegCloseKey(hKey); - } else // Windows NT 3.51 and earlier or Windows 2000 and later - { - res += " "; - res += osvi.szCSDVersion; - res += " (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); - res += buffer; - res += ")"; - } - - break; - - // Test for the Windows 95 product family. - - case VER_PLATFORM_WIN32_WINDOWS: - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { - res += "Microsoft Windows 95"; - if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') { - res += " OSR2"; - } - } - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { - res += "Microsoft Windows 98"; - if (osvi.szCSDVersion[1] == 'A') { - res += " SE"; - } - } - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { - res += "Microsoft Windows Millennium Edition"; - } - break; - - case VER_PLATFORM_WIN32s: - - res += "Microsoft Win32s"; - break; - } -#endif - - return res; -} - -bool SystemTools::ParseURLProtocol(const std::string& URL, - std::string& protocol, - std::string& dataglom) -{ - // match 0 entire url - // match 1 protocol - // match 2 dataglom following protocol:// - kwsys::RegularExpression urlRe(VTK_URL_PROTOCOL_REGEX); - - if (!urlRe.find(URL)) - return false; - - protocol = urlRe.match(1); - dataglom = urlRe.match(2); - - return true; -} - -bool SystemTools::ParseURL(const std::string& URL, std::string& protocol, - std::string& username, std::string& password, - std::string& hostname, std::string& dataport, - std::string& database) -{ - kwsys::RegularExpression urlRe(VTK_URL_REGEX); - if (!urlRe.find(URL)) - return false; - - // match 0 URL - // match 1 protocol - // match 2 mangled user - // match 3 username - // match 4 mangled password - // match 5 password - // match 6 hostname - // match 7 mangled port - // match 8 dataport - // match 9 database name - - protocol = urlRe.match(1); - username = urlRe.match(3); - password = urlRe.match(5); - hostname = urlRe.match(6); - dataport = urlRe.match(8); - database = urlRe.match(9); - - return true; -} - -// These must NOT be initialized. Default initialization to zero is -// necessary. -static unsigned int SystemToolsManagerCount; -SystemToolsTranslationMap* SystemTools::TranslationMap; -#ifdef _WIN32 -SystemToolsPathCaseMap* SystemTools::PathCaseMap; -SystemToolsEnvMap* SystemTools::EnvMap; -#endif -#ifdef __CYGWIN__ -SystemToolsTranslationMap* SystemTools::Cyg2Win32Map; -#endif - -// SystemToolsManager manages the SystemTools singleton. -// SystemToolsManager should be included in any translation unit -// that will use SystemTools or that implements the singleton -// pattern. It makes sure that the SystemTools singleton is created -// before and destroyed after all other singletons in CMake. - -SystemToolsManager::SystemToolsManager() -{ - if (++SystemToolsManagerCount == 1) { - SystemTools::ClassInitialize(); - } -} - -SystemToolsManager::~SystemToolsManager() -{ - if (--SystemToolsManagerCount == 0) { - SystemTools::ClassFinalize(); - } -} - -#if defined(__VMS) -// On VMS we configure the run time C library to be more UNIX like. -// http://h71000.www7.hp.com/doc/732final/5763/5763pro_004.html -extern "C" int decc$feature_get_index(char* name); -extern "C" int decc$feature_set_value(int index, int mode, int value); -static int SetVMSFeature(char* name, int value) -{ - int i; - errno = 0; - i = decc$feature_get_index(name); - return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0); -} -#endif - -void SystemTools::ClassInitialize() -{ -#ifdef __VMS - SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1); -#endif - // Allocate the translation map first. - SystemTools::TranslationMap = new SystemToolsTranslationMap; -#ifdef _WIN32 - SystemTools::PathCaseMap = new SystemToolsPathCaseMap; - SystemTools::EnvMap = new SystemToolsEnvMap; -#endif -#ifdef __CYGWIN__ - SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap; -#endif - -// Add some special translation paths for unix. These are not added -// for windows because drive letters need to be maintained. Also, -// there are not sym-links and mount points on windows anyway. -#if !defined(_WIN32) || defined(__CYGWIN__) - // The tmp path is frequently a logical path so always keep it: - SystemTools::AddKeepPath("/tmp/"); - - // If the current working directory is a logical path then keep the - // logical name. - std::string pwd_str; - if (SystemTools::GetEnv("PWD", pwd_str)) { - char buf[2048]; - if (const char* cwd = Getcwd(buf, 2048)) { - // The current working directory may be a logical path. Find - // the shortest logical path that still produces the correct - // physical path. - std::string cwd_changed; - std::string pwd_changed; - - // Test progressively shorter logical-to-physical mappings. - std::string cwd_str = cwd; - std::string pwd_path; - Realpath(pwd_str.c_str(), pwd_path); - while (cwd_str == pwd_path && cwd_str != pwd_str) { - // The current pair of paths is a working logical mapping. - cwd_changed = cwd_str; - pwd_changed = pwd_str; - - // Strip off one directory level and see if the logical - // mapping still works. - pwd_str = SystemTools::GetFilenamePath(pwd_str); - cwd_str = SystemTools::GetFilenamePath(cwd_str); - Realpath(pwd_str.c_str(), pwd_path); - } - - // Add the translation to keep the logical path name. - if (!cwd_changed.empty() && !pwd_changed.empty()) { - SystemTools::AddTranslationPath(cwd_changed, pwd_changed); - } - } - } -#endif -} - -namespace { - -template -void SafeDelete(T*& pointer) -{ - if (pointer != nullptr) { - delete pointer; - pointer = nullptr; - } -} - -} // end empty namespace - -void SystemTools::ClassFinalize() -{ - SafeDelete(SystemTools::TranslationMap); -#ifdef _WIN32 - SafeDelete(SystemTools::PathCaseMap); - SafeDelete(SystemTools::EnvMap); -#endif -#ifdef __CYGWIN__ - SafeDelete(SystemTools::Cyg2Win32Map); -#endif -} - -} // namespace KWSYS_NAMESPACE - -#if defined(_MSC_VER) && defined(_DEBUG) -#include -#include -#include -namespace KWSYS_NAMESPACE { - -static int SystemToolsDebugReport(int, char* message, int*) -{ - fprintf(stderr, "%s", message); - fflush(stderr); - return 1; // no further reporting required -} - -void SystemTools::EnableMSVCDebugHook() -{ - if (SystemTools::HasEnv("DART_TEST_FROM_DART") || - SystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST")) { - _CrtSetReportHook(SystemToolsDebugReport); - } -} - -} // namespace KWSYS_NAMESPACE -#else -namespace KWSYS_NAMESPACE { -void SystemTools::EnableMSVCDebugHook() -{ -} -} // namespace KWSYS_NAMESPACE -#endif diff --git a/thirdparty/KWSys/adios2sys/SystemTools.hxx.in b/thirdparty/KWSys/adios2sys/SystemTools.hxx.in deleted file mode 100644 index e79e3fcf98..0000000000 --- a/thirdparty/KWSys/adios2sys/SystemTools.hxx.in +++ /dev/null @@ -1,1003 +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 -#include -#include -#include - -#include <@KWSYS_NAMESPACE@/String.hxx> - -#include -// include sys/stat.h after sys/types.h -#include - -#if !defined(_WIN32) || defined(__CYGWIN__) -#include // For access permissions for use with access() -#endif - -// Required for va_list -#include -// Required for FILE* -#include -#if !defined(va_list) -// Some compilers move va_list into the std namespace and there is no way to -// tell that this has been done. Playing with things being included before or -// after stdarg.h does not solve things because we do not have control over -// what the user does. This hack solves this problem by moving va_list to our -// own namespace that is local for kwsys. -namespace std { -} // Required for platforms that do not have std namespace -namespace @KWSYS_NAMESPACE@_VA_LIST { -using namespace std; -typedef va_list hack_va_list; -} -namespace @KWSYS_NAMESPACE@ { -typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list; -} -#endif // va_list - -namespace @KWSYS_NAMESPACE@ { - -class SystemToolsTranslationMap; -class SystemToolsPathCaseMap; -class SystemToolsEnvMap; - -/** \class SystemToolsManager - * \brief Use to make sure SystemTools is initialized before it is used - * and is the last static object destroyed - */ -class @KWSYS_NAMESPACE@_EXPORT SystemToolsManager -{ -public: - SystemToolsManager(); - ~SystemToolsManager(); -}; - -// This instance will show up in any translation unit that uses -// SystemTools. It will make sure SystemTools is initialized -// before it is used and is the last static object destroyed. -static SystemToolsManager SystemToolsManagerInstance; - -// Flags for use with TestFileAccess. Use a typedef in case any operating -// system in the future needs a special type. These are flags that may be -// combined using the | operator. -typedef int TestFilePermissions; -#if defined(_WIN32) && !defined(__CYGWIN__) -// On Windows (VC and Borland), no system header defines these constants... -static const TestFilePermissions TEST_FILE_OK = 0; -static const TestFilePermissions TEST_FILE_READ = 4; -static const TestFilePermissions TEST_FILE_WRITE = 2; -static const TestFilePermissions TEST_FILE_EXECUTE = 1; -#else -// Standard POSIX constants -static const TestFilePermissions TEST_FILE_OK = F_OK; -static const TestFilePermissions TEST_FILE_READ = R_OK; -static const TestFilePermissions TEST_FILE_WRITE = W_OK; -static const TestFilePermissions TEST_FILE_EXECUTE = X_OK; -#endif - -/** \class SystemTools - * \brief A collection of useful platform-independent system functions. - */ -class @KWSYS_NAMESPACE@_EXPORT SystemTools -{ -public: - /** ----------------------------------------------------------------- - * String Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Replace symbols in str that are not valid in C identifiers as - * defined by the 1999 standard, ie. anything except [A-Za-z0-9_]. - * They are replaced with `_' and if the first character is a digit - * then an underscore is prepended. Note that this can produce - * identifiers that the standard reserves (_[A-Z].* and __.*). - */ - static std::string MakeCidentifier(const std::string& s); - - static std::string MakeCindentifier(const std::string& s) - { - return MakeCidentifier(s); - } - - /** - * Replace replace all 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 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& l); - static bool Split(const std::string& s, std::vector& l, - char separator); - - /** - * Return string with space added between capitalized words - * (i.e. EatMyShorts becomes Eat My Shorts ) - * (note that IEatShorts becomes IEat Shorts) - */ - static std::string AddSpaceBetweenCapitalizedWords(const std::string&); - - /** - * Append two or more strings and produce new one. - * Programmer must 'delete []' the resulting string, which was allocated - * with 'new'. - * Return 0 if inputs are empty or there was an error - */ - static char* AppendStrings(const char* str1, const char* str2); - static char* AppendStrings(const char* str1, const char* str2, - const char* str3); - - /** - * Estimate the length of the string that will be produced - * from printing the given format string and arguments. The - * returned length will always be at least as large as the string - * that will result from printing. - * WARNING: since va_arg is called to iterate of the argument list, - * you will not be able to use this 'ap' anymore from the beginning. - * It's up to you to call va_end though. - */ - static int EstimateFormatLength(const char* format, va_list ap); - - /** - * Escape specific characters in 'str'. - */ - static std::string EscapeChars(const char* str, const char* chars_to_escape, - char escape_char = '\\'); - - /** ----------------------------------------------------------------- - * Filename Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Replace Windows file system slashes with Unix-style slashes. - */ - static void ConvertToUnixSlashes(std::string& path); - -#ifdef _WIN32 - /** Calls Encoding::ToWindowsExtendedPath. */ - static std::wstring ConvertToWindowsExtendedPath(const std::string&); -#endif - - /** - * For windows this calls ConvertToWindowsOutputPath and for unix - * it calls ConvertToUnixOutputPath - */ - static std::string ConvertToOutputPath(const std::string&); - - /** - * Convert the path to a string that can be used in a unix makefile. - * double slashes are removed, and spaces are escaped. - */ - static std::string ConvertToUnixOutputPath(const std::string&); - - /** - * Convert the path to string that can be used in a windows project or - * makefile. Double slashes are removed if they are not at the start of - * the string, the slashes are converted to windows style backslashes, and - * if there are spaces in the string it is double quoted. - */ - static std::string ConvertToWindowsOutputPath(const std::string&); - - /** - * Return true if a path with the given name exists in the current directory. - */ - static bool PathExists(const std::string& path); - - /** - * Return true if a file exists in the current directory. - * If isFile = true, then make sure the file is a file and - * not a directory. If isFile = false, then return true - * if it is a file or a directory. Note that the file will - * also be checked for read access. (Currently, this check - * for read access is only done on POSIX systems.) - */ - static bool FileExists(const char* filename, bool isFile); - static bool FileExists(const std::string& filename, bool isFile); - static bool FileExists(const char* filename); - static bool FileExists(const std::string& filename); - - /** - * Test if a file exists and can be accessed with the requested - * permissions. Symbolic links are followed. Returns true if - * the access test was successful. - * - * On POSIX systems (including Cygwin), this maps to the access - * function. On Windows systems, all existing files are - * considered readable, and writable files are considered to - * have the read-only file attribute cleared. - */ - static bool TestFileAccess(const char* filename, - TestFilePermissions permissions); - static bool TestFileAccess(const std::string& filename, - TestFilePermissions permissions); -/** - * Cross platform wrapper for stat struct - */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#if defined(__BORLANDC__) - typedef struct stati64 Stat_t; -#else - typedef struct _stat64 Stat_t; -#endif -#else - typedef struct stat Stat_t; -#endif - - /** - * Cross platform wrapper for stat system call - * - * On Windows this may not work for paths longer than 250 characters - * due to limitations of the underlying '_wstat64' call. - */ - static int Stat(const char* path, Stat_t* buf); - static int Stat(const std::string& path, Stat_t* buf); - -/** - * Converts Cygwin path to Win32 path. Uses dictionary container for - * caching and calls to cygwin_conv_to_win32_path from Cygwin dll - * for actual translation. Returns true on success, else false. - */ -#ifdef __CYGWIN__ - static bool PathCygwinToWin32(const char* path, char* win32_path); -#endif - - /** - * Return file length - */ - static unsigned long FileLength(const std::string& filename); - - /** - Change the modification time or create a file - */ - static bool Touch(const std::string& filename, bool create); - - /** - * Compare file modification times. - * Return true for successful comparison and false for error. - * When true is returned, result has -1, 0, +1 for - * f1 older, same, or newer than f2. - */ - static bool FileTimeCompare(const std::string& f1, const std::string& f2, - int* result); - - /** - * Get the file extension (including ".") needed for an executable - * on the current platform ("" for unix, ".exe" for Windows). - */ - static const char* GetExecutableExtension(); - - /** - * Given a path on a Windows machine, return the actual case of - * the path as it exists on disk. Path components that do not - * exist on disk are returned unchanged. Relative paths are always - * returned unchanged. Drive letters are always made upper case. - * This does nothing on non-Windows systems but return the path. - */ - static std::string GetActualCaseForPath(const std::string& path); - - /** - * Given the path to a program executable, get the directory part of - * the path with the file stripped off. If there is no directory - * part, the empty string is returned. - */ - static std::string GetProgramPath(const std::string&); - static bool SplitProgramPath(const std::string& in_name, std::string& dir, - std::string& file, bool errorReport = true); - - /** - * Given argv[0] for a unix program find the full path to a running - * executable. argv0 can be null for windows WinMain programs - * in this case GetModuleFileName will be used to find the path - * to the running executable. If argv0 is not a full path, - * then this will try to find the full path. If the path is not - * found false is returned, if found true is returned. An error - * message of the attempted paths is stored in errorMsg. - * exeName is the name of the executable. - * buildDir is a possibly null path to the build directory. - * installPrefix is a possibly null pointer to the install directory. - */ - static bool FindProgramPath(const char* argv0, std::string& pathOut, - std::string& errorMsg, const char* exeName = 0, - const char* buildDir = 0, - const char* installPrefix = 0); - - /** - * Given a path to a file or directory, convert it to a full path. - * This collapses away relative paths relative to the cwd argument - * (which defaults to the current working directory). The full path - * is returned. - */ - static std::string CollapseFullPath(const std::string& in_relative); - static std::string CollapseFullPath(const std::string& in_relative, - const char* in_base); - static std::string CollapseFullPath(const std::string& in_relative, - const std::string& in_base); - - /** - * Get the real path for a given path, removing all symlinks. In - * the event of an error (non-existent path, permissions issue, - * etc.) the original path is returned if errorMessage pointer is - * NULL. Otherwise empty string is returned and errorMessage - * contains error description. - */ - static std::string GetRealPath(const std::string& path, - std::string* errorMessage = 0); - - /** - * Split a path name into its root component and the rest of the - * path. The root component is one of the following: - * "/" = UNIX full path - * "c:/" = Windows full path (can be any drive letter) - * "c:" = Windows drive-letter relative path (can be any drive letter) - * "//" = Network path - * "~/" = Home path for current user - * "~u/" = Home path for user 'u' - * "" = Relative path - * - * A pointer to the rest of the path after the root component is - * returned. The root component is stored in the "root" string if - * given. - */ - static const char* SplitPathRootComponent(const std::string& p, - std::string* root = 0); - - /** - * Split a path name into its basic components. The first component - * always exists and is the root returned by SplitPathRootComponent. - * The remaining components form the path. If there is a trailing - * slash then the last component is the empty string. The - * components can be recombined as "c[0]c[1]/c[2]/.../c[n]" to - * produce the original path. Home directory references are - * automatically expanded if expand_home_dir is true and this - * platform supports them. - * - * 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& 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& components); - static std::string JoinPath(std::vector::const_iterator first, - std::vector::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 get everything. Due to a buggy stream - * library on the HP and another on Mac OS X, we need this very carefully - * written version of getline. Returns true if any data were read before the - * end-of-file was reached. If the has_newline argument is specified, it will - * be true when the line read had a newline character. - */ - static bool GetLineFromStream(std::istream& istr, std::string& line, - bool* has_newline = 0, long sizeLimit = -1); - - /** - * Get the parent directory of the directory or file - */ - static std::string GetParentDirectory(const std::string& fileOrDir); - - /** - * Check if the given file or directory is in subdirectory of dir - */ - static bool IsSubDirectory(const std::string& fileOrDir, - const std::string& dir); - - /** ----------------------------------------------------------------- - * File Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Open a file considering unicode. - */ - static FILE* Fopen(const std::string& file, const char* mode); - -/** - * 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 = 0); - static bool MakeDirectory(const std::string& path, const mode_t* mode = 0); - - /** - * Copy the source file to the destination file only - * if the two files differ. - */ - static bool CopyFileIfDifferent(const std::string& source, - const std::string& destination); - - /** - * Compare the contents of two files. Return true if different - */ - static bool FilesDiffer(const std::string& source, - const std::string& destination); - - /** - * Return true if the two files are the same file - */ - static bool SameFile(const std::string& file1, const std::string& file2); - - /** - * Copy a file. - */ - static bool CopyFileAlways(const std::string& source, - const std::string& destination); - - /** - * Copy a file. If the "always" argument is true the file is always - * copied. If it is false, the file is copied only if it is new or - * has changed. - */ - static bool CopyAFile(const std::string& source, - const std::string& destination, bool always = true); - - /** - * Copy content directory to another directory with all files and - * subdirectories. If the "always" argument is true all files are - * always copied. If it is false, only files that have changed or - * are new are copied. - */ - static bool CopyADirectory(const std::string& source, - const std::string& destination, - bool always = true); - - /** - * Remove a file - */ - static bool RemoveFile(const std::string& source); - - /** - * Remove a directory - */ - static bool RemoveADirectory(const std::string& source); - - /** - * Get the maximum full file path length - */ - static size_t GetMaximumFilePathLength(); - - /** - * Find a file in the system PATH, with optional extra paths - */ - static std::string FindFile( - const std::string& name, - const std::vector& path = std::vector(), - 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& path = std::vector(), - 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& path = std::vector(), - bool no_system_path = false); - static std::string FindProgram( - const std::string& name, - const std::vector& path = std::vector(), - bool no_system_path = false); - static std::string FindProgram( - const std::vector& names, - const std::vector& path = std::vector(), - 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& 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& 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& path, const char* env = 0); - - /** - * Read an environment variable - */ - static const char* GetEnv(const char* key); - static const char* GetEnv(const std::string& key); - static bool GetEnv(const char* key, std::string& result); - static bool GetEnv(const std::string& key, std::string& result); - static bool HasEnv(const char* key); - static bool HasEnv(const std::string& key); - - /** Put a string into the environment - of the form var=value */ - static bool PutEnv(const std::string& env); - - /** Remove a string from the environment. - Input is of the form "var" or "var=value" (value is ignored). */ - static bool UnPutEnv(const std::string& env); - - /** - * Get current working directory CWD - */ - static std::string GetCurrentWorkingDirectory(bool collapse = true); - - /** - * Change directory to the directory specified - */ - static int ChangeDirectory(const std::string& dir); - - /** - * Get the result of strerror(errno) - */ - static std::string GetLastSystemError(); - - /** - * When building DEBUG with MSVC, this enables a hook that prevents - * error dialogs from popping up if the program is being run from - * DART. - */ - static void EnableMSVCDebugHook(); - - /** - * Get the width of the terminal window. The code may or may not work, so - * make sure you have some reasonable defaults prepared if the code returns - * some bogus size. - */ - static int GetTerminalWidth(); - - /** - * Add an entry in the path translation table. - */ - static void AddTranslationPath(const std::string& dir, - const std::string& refdir); - - /** - * If dir is different after CollapseFullPath is called, - * Then insert it into the path translation table - */ - static void AddKeepPath(const std::string& dir); - - /** - * Update path by going through the Path Translation table; - */ - static void CheckTranslationPath(std::string& path); - - /** - * Delay the execution for a specified amount of time specified - * in 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; - } - - /** - * 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& path = std::vector(), - bool no_system_path = false); - - static const char* GetEnvImpl(const char* key); - - /** - * Path translation table from dir to refdir - * Each time 'dir' will be found it will be replace by 'refdir' - */ - static SystemToolsTranslationMap* TranslationMap; -#ifdef _WIN32 - static std::string GetActualCaseForPathCached(std::string const& path); - static SystemToolsPathCaseMap* PathCaseMap; - static SystemToolsEnvMap* EnvMap; -#endif -#ifdef __CYGWIN__ - static SystemToolsTranslationMap* Cyg2Win32Map; -#endif - friend class SystemToolsManager; -}; - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/Terminal.c b/thirdparty/KWSys/adios2sys/Terminal.c deleted file mode 100644 index eaa5c7d43c..0000000000 --- a/thirdparty/KWSys/adios2sys/Terminal.c +++ /dev/null @@ -1,402 +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 /* va_list */ -#include /* getenv */ -#include /* strcmp */ - -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) -#include /* _get_osfhandle */ -#include /* SetConsoleTextAttribute */ -#endif - -#if defined(KWSYS_TERMINAL_ISATTY_WORKS) -#include /* isatty */ -#else -#include /* fstat */ -#endif - -static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, - int default_tty); -static void kwsysTerminalSetVT100Color(FILE* stream, int color); -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) -static HANDLE kwsysTerminalGetStreamHandle(FILE* stream); -static void kwsysTerminalSetConsoleColor(HANDLE hOut, - CONSOLE_SCREEN_BUFFER_INFO* hOutInfo, - FILE* stream, int color); -#endif - -void kwsysTerminal_cfprintf(int color, FILE* stream, const char* format, ...) -{ - /* Setup the stream with the given color if possible. */ - int pipeIsConsole = 0; - int pipeIsVT100 = 0; - int default_vt100 = color & kwsysTerminal_Color_AssumeVT100; - int default_tty = color & kwsysTerminal_Color_AssumeTTY; -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) - CONSOLE_SCREEN_BUFFER_INFO hOutInfo; - HANDLE hOut = kwsysTerminalGetStreamHandle(stream); - if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) { - pipeIsConsole = 1; - kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, color); - } -#endif - if (!pipeIsConsole && - kwsysTerminalStreamIsVT100(stream, default_vt100, default_tty)) { - pipeIsVT100 = 1; - kwsysTerminalSetVT100Color(stream, color); - } - - /* Format the text into the stream. */ - { - va_list var_args; - va_start(var_args, format); - vfprintf(stream, format, var_args); - va_end(var_args); - } - -/* Restore the normal color state for the stream. */ -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) - if (pipeIsConsole) { - kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, - kwsysTerminal_Color_Normal); - } -#endif - if (pipeIsVT100) { - kwsysTerminalSetVT100Color(stream, kwsysTerminal_Color_Normal); - } -} - -/* Detect cases when a stream is definitely not interactive. */ -#if !defined(KWSYS_TERMINAL_ISATTY_WORKS) -static int kwsysTerminalStreamIsNotInteractive(FILE* stream) -{ - /* The given stream is definitely not interactive if it is a regular - file. */ - struct stat stream_stat; - if (fstat(fileno(stream), &stream_stat) == 0) { - if (stream_stat.st_mode & S_IFREG) { - return 1; - } - } - return 0; -} -#endif - -/* List of terminal names known to support VT100 color escape sequences. */ -static const char* kwsysTerminalVT100Names[] = { "Eterm", - "ansi", - "color-xterm", - "con132x25", - "con132x30", - "con132x43", - "con132x60", - "con80x25", - "con80x28", - "con80x30", - "con80x43", - "con80x50", - "con80x60", - "cons25", - "console", - "cygwin", - "dtterm", - "eterm-color", - "gnome", - "gnome-256color", - "konsole", - "konsole-256color", - "kterm", - "linux", - "msys", - "linux-c", - "mach-color", - "mlterm", - "putty", - "putty-256color", - "rxvt", - "rxvt-256color", - "rxvt-cygwin", - "rxvt-cygwin-native", - "rxvt-unicode", - "rxvt-unicode-256color", - "screen", - "screen-256color", - "screen-256color-bce", - "screen-bce", - "screen-w", - "screen.linux", - "tmux", - "tmux-256color", - "vt100", - "xterm", - "xterm-16color", - "xterm-256color", - "xterm-88color", - "xterm-color", - "xterm-debian", - "xterm-termite", - 0 }; - -/* Detect whether a stream is displayed in a VT100-compatible terminal. */ -static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, - int default_tty) -{ - /* Force color according to http://bixense.com/clicolors/ convention. */ - { - const char* clicolor_force = getenv("CLICOLOR_FORCE"); - if (clicolor_force && *clicolor_force && - strcmp(clicolor_force, "0") != 0) { - return 1; - } - } - - /* If running inside emacs the terminal is not VT100. Some emacs - seem to claim the TERM is xterm even though they do not support - VT100 escapes. */ - { - const char* emacs = getenv("EMACS"); - if (emacs && *emacs == 't') { - return 0; - } - } - - /* Check for a valid terminal. */ - if (!default_vt100) { - const char** t = 0; - const char* term = getenv("TERM"); - if (term) { - for (t = kwsysTerminalVT100Names; *t && strcmp(term, *t) != 0; ++t) { - } - } - if (!(t && *t)) { - return 0; - } - } - -#if defined(KWSYS_TERMINAL_ISATTY_WORKS) - /* Make sure the stream is a tty. */ - (void)default_tty; - return isatty(fileno(stream)) ? 1 : 0; -#else - /* Check for cases in which the stream is definitely not a tty. */ - if (kwsysTerminalStreamIsNotInteractive(stream)) { - return 0; - } - - /* Use the provided default for whether this is a tty. */ - return default_tty; -#endif -} - -/* VT100 escape sequence strings. */ -#define KWSYS_TERMINAL_VT100_NORMAL "\33[0m" -#define KWSYS_TERMINAL_VT100_BOLD "\33[1m" -#define KWSYS_TERMINAL_VT100_UNDERLINE "\33[4m" -#define KWSYS_TERMINAL_VT100_BLINK "\33[5m" -#define KWSYS_TERMINAL_VT100_INVERSE "\33[7m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_BLACK "\33[30m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_RED "\33[31m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_GREEN "\33[32m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW "\33[33m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_BLUE "\33[34m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA "\33[35m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_CYAN "\33[36m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_WHITE "\33[37m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_BLACK "\33[40m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_RED "\33[41m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_GREEN "\33[42m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW "\33[43m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_BLUE "\33[44m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA "\33[45m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_CYAN "\33[46m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_WHITE "\33[47m" - -/* Write VT100 escape sequences to the stream for the given color. */ -static void kwsysTerminalSetVT100Color(FILE* stream, int color) -{ - if (color == kwsysTerminal_Color_Normal) { - fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL); - return; - } - - switch (color & kwsysTerminal_Color_ForegroundMask) { - case kwsysTerminal_Color_Normal: - fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL); - break; - case kwsysTerminal_Color_ForegroundBlack: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLACK); - break; - case kwsysTerminal_Color_ForegroundRed: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_RED); - break; - case kwsysTerminal_Color_ForegroundGreen: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_GREEN); - break; - case kwsysTerminal_Color_ForegroundYellow: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW); - break; - case kwsysTerminal_Color_ForegroundBlue: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLUE); - break; - case kwsysTerminal_Color_ForegroundMagenta: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA); - break; - case kwsysTerminal_Color_ForegroundCyan: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_CYAN); - break; - case kwsysTerminal_Color_ForegroundWhite: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_WHITE); - break; - } - switch (color & kwsysTerminal_Color_BackgroundMask) { - case kwsysTerminal_Color_BackgroundBlack: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLACK); - break; - case kwsysTerminal_Color_BackgroundRed: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_RED); - break; - case kwsysTerminal_Color_BackgroundGreen: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_GREEN); - break; - case kwsysTerminal_Color_BackgroundYellow: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW); - break; - case kwsysTerminal_Color_BackgroundBlue: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLUE); - break; - case kwsysTerminal_Color_BackgroundMagenta: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA); - break; - case kwsysTerminal_Color_BackgroundCyan: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_CYAN); - break; - case kwsysTerminal_Color_BackgroundWhite: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_WHITE); - break; - } - if (color & kwsysTerminal_Color_ForegroundBold) { - fprintf(stream, KWSYS_TERMINAL_VT100_BOLD); - } -} - -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) - -#define KWSYS_TERMINAL_MASK_FOREGROUND \ - (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY) -#define KWSYS_TERMINAL_MASK_BACKGROUND \ - (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY) - -/* Get the Windows handle for a FILE stream. */ -static HANDLE kwsysTerminalGetStreamHandle(FILE* stream) -{ - /* Get the C-library file descriptor from the stream. */ - int fd = fileno(stream); - -#if defined(__CYGWIN__) - /* Cygwin seems to have an extra pipe level. If the file descriptor - corresponds to stdout or stderr then obtain the matching windows - handle directly. */ - if (fd == fileno(stdout)) { - return GetStdHandle(STD_OUTPUT_HANDLE); - } else if (fd == fileno(stderr)) { - return GetStdHandle(STD_ERROR_HANDLE); - } -#endif - - /* Get the underlying Windows handle for the descriptor. */ - return (HANDLE)_get_osfhandle(fd); -} - -/* Set color attributes in a Windows console. */ -static void kwsysTerminalSetConsoleColor(HANDLE hOut, - CONSOLE_SCREEN_BUFFER_INFO* hOutInfo, - FILE* stream, int color) -{ - WORD attributes = 0; - switch (color & kwsysTerminal_Color_ForegroundMask) { - case kwsysTerminal_Color_Normal: - attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_FOREGROUND; - break; - case kwsysTerminal_Color_ForegroundBlack: - attributes |= 0; - break; - case kwsysTerminal_Color_ForegroundRed: - attributes |= FOREGROUND_RED; - break; - case kwsysTerminal_Color_ForegroundGreen: - attributes |= FOREGROUND_GREEN; - break; - case kwsysTerminal_Color_ForegroundYellow: - attributes |= FOREGROUND_RED | FOREGROUND_GREEN; - break; - case kwsysTerminal_Color_ForegroundBlue: - attributes |= FOREGROUND_BLUE; - break; - case kwsysTerminal_Color_ForegroundMagenta: - attributes |= FOREGROUND_RED | FOREGROUND_BLUE; - break; - case kwsysTerminal_Color_ForegroundCyan: - attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN; - break; - case kwsysTerminal_Color_ForegroundWhite: - attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; - break; - } - switch (color & kwsysTerminal_Color_BackgroundMask) { - case kwsysTerminal_Color_Normal: - attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_BACKGROUND; - break; - case kwsysTerminal_Color_BackgroundBlack: - attributes |= 0; - break; - case kwsysTerminal_Color_BackgroundRed: - attributes |= BACKGROUND_RED; - break; - case kwsysTerminal_Color_BackgroundGreen: - attributes |= BACKGROUND_GREEN; - break; - case kwsysTerminal_Color_BackgroundYellow: - attributes |= BACKGROUND_RED | BACKGROUND_GREEN; - break; - case kwsysTerminal_Color_BackgroundBlue: - attributes |= BACKGROUND_BLUE; - break; - case kwsysTerminal_Color_BackgroundMagenta: - attributes |= BACKGROUND_RED | BACKGROUND_BLUE; - break; - case kwsysTerminal_Color_BackgroundCyan: - attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN; - break; - case kwsysTerminal_Color_BackgroundWhite: - attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; - break; - } - if (color & kwsysTerminal_Color_ForegroundBold) { - attributes |= FOREGROUND_INTENSITY; - } - if (color & kwsysTerminal_Color_BackgroundBold) { - attributes |= BACKGROUND_INTENSITY; - } - fflush(stream); - SetConsoleTextAttribute(hOut, attributes); -} -#endif diff --git a/thirdparty/KWSys/adios2sys/Terminal.h.in b/thirdparty/KWSys/adios2sys/Terminal.h.in deleted file mode 100644 index 5d29830042..0000000000 --- a/thirdparty/KWSys/adios2sys/Terminal.h.in +++ /dev/null @@ -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 /* For file stream type FILE. */ - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -#define kwsys_ns(x) @KWSYS_NAMESPACE@##x -#define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#define kwsysTerminal_cfprintf kwsys_ns(Terminal_cfprintf) -#define kwsysTerminal_Color_e kwsys_ns(Terminal_Color_e) -#define kwsysTerminal_Color_Normal kwsys_ns(Terminal_Color_Normal) -#define kwsysTerminal_Color_ForegroundBlack \ - kwsys_ns(Terminal_Color_ForegroundBlack) -#define kwsysTerminal_Color_ForegroundRed \ - kwsys_ns(Terminal_Color_ForegroundRed) -#define kwsysTerminal_Color_ForegroundGreen \ - kwsys_ns(Terminal_Color_ForegroundGreen) -#define kwsysTerminal_Color_ForegroundYellow \ - kwsys_ns(Terminal_Color_ForegroundYellow) -#define kwsysTerminal_Color_ForegroundBlue \ - kwsys_ns(Terminal_Color_ForegroundBlue) -#define kwsysTerminal_Color_ForegroundMagenta \ - kwsys_ns(Terminal_Color_ForegroundMagenta) -#define kwsysTerminal_Color_ForegroundCyan \ - kwsys_ns(Terminal_Color_ForegroundCyan) -#define kwsysTerminal_Color_ForegroundWhite \ - kwsys_ns(Terminal_Color_ForegroundWhite) -#define kwsysTerminal_Color_ForegroundMask \ - kwsys_ns(Terminal_Color_ForegroundMask) -#define kwsysTerminal_Color_BackgroundBlack \ - kwsys_ns(Terminal_Color_BackgroundBlack) -#define kwsysTerminal_Color_BackgroundRed \ - kwsys_ns(Terminal_Color_BackgroundRed) -#define kwsysTerminal_Color_BackgroundGreen \ - kwsys_ns(Terminal_Color_BackgroundGreen) -#define kwsysTerminal_Color_BackgroundYellow \ - kwsys_ns(Terminal_Color_BackgroundYellow) -#define kwsysTerminal_Color_BackgroundBlue \ - kwsys_ns(Terminal_Color_BackgroundBlue) -#define kwsysTerminal_Color_BackgroundMagenta \ - kwsys_ns(Terminal_Color_BackgroundMagenta) -#define kwsysTerminal_Color_BackgroundCyan \ - kwsys_ns(Terminal_Color_BackgroundCyan) -#define kwsysTerminal_Color_BackgroundWhite \ - kwsys_ns(Terminal_Color_BackgroundWhite) -#define kwsysTerminal_Color_BackgroundMask \ - kwsys_ns(Terminal_Color_BackgroundMask) -#define kwsysTerminal_Color_ForegroundBold \ - kwsys_ns(Terminal_Color_ForegroundBold) -#define kwsysTerminal_Color_BackgroundBold \ - kwsys_ns(Terminal_Color_BackgroundBold) -#define kwsysTerminal_Color_AssumeTTY kwsys_ns(Terminal_Color_AssumeTTY) -#define kwsysTerminal_Color_AssumeVT100 kwsys_ns(Terminal_Color_AssumeVT100) -#define kwsysTerminal_Color_AttributeMask \ - kwsys_ns(Terminal_Color_AttributeMask) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Write colored and formatted text to a stream. Color is used only - * for streams supporting it. The color specification is constructed - * by bitwise-OR-ing enumeration values. At most one foreground and - * one background value may be given. - * - * Whether the a stream supports color is usually automatically - * detected, but with two exceptions: - * - * - When the stream is displayed in a terminal supporting VT100 - * color but using an intermediate pipe for communication the - * detection of a tty fails. (This typically occurs for a shell - * running in an rxvt terminal in MSYS.) If the caller knows this - * to be the case, the attribute Color_AssumeTTY may be included in - * the color specification. - * - * - When the stream is displayed in a terminal whose TERM - * environment variable is not set or is set to a value that is not - * known to support VT100 colors. If the caller knows this to be - * the case, the attribute Color_AssumeVT100 may be included in the - * color specification. - */ -kwsysEXPORT void kwsysTerminal_cfprintf(int color, FILE* stream, - const char* format, ...); -enum kwsysTerminal_Color_e -{ - /* Normal Text */ - kwsysTerminal_Color_Normal = 0, - - /* Foreground Color */ - kwsysTerminal_Color_ForegroundBlack = 0x1, - kwsysTerminal_Color_ForegroundRed = 0x2, - kwsysTerminal_Color_ForegroundGreen = 0x3, - kwsysTerminal_Color_ForegroundYellow = 0x4, - kwsysTerminal_Color_ForegroundBlue = 0x5, - kwsysTerminal_Color_ForegroundMagenta = 0x6, - kwsysTerminal_Color_ForegroundCyan = 0x7, - kwsysTerminal_Color_ForegroundWhite = 0x8, - kwsysTerminal_Color_ForegroundMask = 0xF, - - /* Background Color */ - kwsysTerminal_Color_BackgroundBlack = 0x10, - kwsysTerminal_Color_BackgroundRed = 0x20, - kwsysTerminal_Color_BackgroundGreen = 0x30, - kwsysTerminal_Color_BackgroundYellow = 0x40, - kwsysTerminal_Color_BackgroundBlue = 0x50, - kwsysTerminal_Color_BackgroundMagenta = 0x60, - kwsysTerminal_Color_BackgroundCyan = 0x70, - kwsysTerminal_Color_BackgroundWhite = 0x80, - kwsysTerminal_Color_BackgroundMask = 0xF0, - - /* Attributes */ - kwsysTerminal_Color_ForegroundBold = 0x100, - kwsysTerminal_Color_BackgroundBold = 0x200, - kwsysTerminal_Color_AssumeTTY = 0x400, - kwsysTerminal_Color_AssumeVT100 = 0x800, - kwsysTerminal_Color_AttributeMask = 0xF00 -}; - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -#undef kwsys_ns -#undef kwsysEXPORT -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -#undef kwsysTerminal_cfprintf -#undef kwsysTerminal_Color_e -#undef kwsysTerminal_Color_Normal -#undef kwsysTerminal_Color_ForegroundBlack -#undef kwsysTerminal_Color_ForegroundRed -#undef kwsysTerminal_Color_ForegroundGreen -#undef kwsysTerminal_Color_ForegroundYellow -#undef kwsysTerminal_Color_ForegroundBlue -#undef kwsysTerminal_Color_ForegroundMagenta -#undef kwsysTerminal_Color_ForegroundCyan -#undef kwsysTerminal_Color_ForegroundWhite -#undef kwsysTerminal_Color_ForegroundMask -#undef kwsysTerminal_Color_BackgroundBlack -#undef kwsysTerminal_Color_BackgroundRed -#undef kwsysTerminal_Color_BackgroundGreen -#undef kwsysTerminal_Color_BackgroundYellow -#undef kwsysTerminal_Color_BackgroundBlue -#undef kwsysTerminal_Color_BackgroundMagenta -#undef kwsysTerminal_Color_BackgroundCyan -#undef kwsysTerminal_Color_BackgroundWhite -#undef kwsysTerminal_Color_BackgroundMask -#undef kwsysTerminal_Color_ForegroundBold -#undef kwsysTerminal_Color_BackgroundBold -#undef kwsysTerminal_Color_AssumeTTY -#undef kwsysTerminal_Color_AssumeVT100 -#undef kwsysTerminal_Color_AttributeMask -#endif -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/hash_fun.hxx.in b/thirdparty/KWSys/adios2sys/hash_fun.hxx.in deleted file mode 100644 index 8626c2aa2a..0000000000 --- a/thirdparty/KWSys/adios2sys/hash_fun.hxx.in +++ /dev/null @@ -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 // size_t -#include - -namespace @KWSYS_NAMESPACE@ { - -template -struct hash -{ -}; - -inline size_t _stl_hash_string(const char* __s) -{ - unsigned long __h = 0; - for (; *__s; ++__s) - __h = 5 * __h + *__s; - - return size_t(__h); -} - -template <> -struct hash -{ - size_t operator()(const char* __s) const { return _stl_hash_string(__s); } -}; - -template <> -struct hash -{ - size_t operator()(const char* __s) const { return _stl_hash_string(__s); } -}; - -template <> -struct hash -{ - size_t operator()(const std::string& __s) const - { - return _stl_hash_string(__s.c_str()); - } -}; - -#if !defined(__BORLANDC__) -template <> -struct hash -{ - size_t operator()(const std::string& __s) const - { - return _stl_hash_string(__s.c_str()); - } -}; -#endif - -template <> -struct hash -{ - size_t operator()(char __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned char __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned char __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(short __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned short __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(int __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned int __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(long __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned long __x) const { return __x; } -}; - -// use long long or __int64 -#if @KWSYS_USE_LONG_LONG@ -template <> -struct hash -{ - size_t operator()(long long __x) const { return __x; } -}; - -template <> -struct hash -{ - 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 -{ - size_t operator()(unsigned __int64 __x) const { return __x; } -}; -#endif // use long long or __int64 - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/thirdparty/KWSys/adios2sys/hash_map.hxx.in b/thirdparty/KWSys/adios2sys/hash_map.hxx.in deleted file mode 100644 index 8c9b81e1b9..0000000000 --- a/thirdparty/KWSys/adios2sys/hash_map.hxx.in +++ /dev/null @@ -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 // equal_to - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4284) -#pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -#pragma set woff 1174 -#pragma set woff 1375 -#endif - -namespace @KWSYS_NAMESPACE@ { - -// select1st is an extension: it is not part of the standard. -template -struct hash_select1st -{ - const T1& operator()(const std::pair& __x) const - { - return __x.first; - } -}; - -// Forward declaration of equality operator; needed for friend declaration. - -template , - class _EqualKey = std::equal_to<_Key>, - class _Alloc = std::allocator > -class hash_map; - -template -bool operator==(const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&, - const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&); - -template -class hash_map -{ -private: - typedef hashtable, _Key, _HashFcn, - hash_select1st, _EqualKey, _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef _Tp data_type; - typedef _Tp mapped_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_map() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_map(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_map(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_map(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template - hash_map(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_map(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_map(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_map(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_unique(__f, __l); - } - -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 insert(const value_type& __obj) - { - return _M_ht.insert_unique(__obj); - } - template - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_unique(__f, __l); - } - std::pair insert_noresize(const value_type& __obj) - { - return _M_ht.insert_unique_noresize(__obj); - } - - iterator find(const key_type& __key) { return _M_ht.find(__key); } - const_iterator find(const key_type& __key) const - { - return _M_ht.find(__key); - } - - _Tp& operator[](const key_type& __key) - { - return _M_ht.find_or_insert(value_type(__key, _Tp())).second; - } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair equal_range(const key_type& __key) - { - return _M_ht.equal_range(__key); - } - std::pair equal_range( - const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template -bool operator==(const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - return __hm1._M_ht == __hm2._M_ht; -} - -template -inline bool operator!=( - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - return !(__hm1 == __hm2); -} - -template -inline void swap(hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - __hm1.swap(__hm2); -} - -// Forward declaration of equality operator; needed for friend declaration. - -template , - class _EqualKey = std::equal_to<_Key>, - class _Alloc = std::allocator > -class hash_multimap; - -template -bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2); - -template -class hash_multimap -{ -private: - typedef hashtable, _Key, _HashFcn, - hash_select1st, _EqualKey, _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef _Tp data_type; - typedef _Tp mapped_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_multimap() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_multimap(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_multimap(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_multimap(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template - hash_multimap(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_equal(__f, __l); - } - -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 - 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 equal_range(const key_type& __key) - { - return _M_ht.equal_range(__key); - } - std::pair equal_range( - const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template -bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2) -{ - return __hm1._M_ht == __hm2._M_ht; -} - -template -inline bool operator!=( - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2) -{ - return !(__hm1 == __hm2); -} - -template -inline void swap(hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - __hm1.swap(__hm2); -} - -} // namespace @KWSYS_NAMESPACE@ - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -#pragma reset woff 1174 -#pragma reset woff 1375 -#endif - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/hash_set.hxx.in b/thirdparty/KWSys/adios2sys/hash_set.hxx.in deleted file mode 100644 index 5edd367af7..0000000000 --- a/thirdparty/KWSys/adios2sys/hash_set.hxx.in +++ /dev/null @@ -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 // equal_to - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4284) -#pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -#pragma set woff 1174 -#pragma set woff 1375 -#endif - -namespace @KWSYS_NAMESPACE@ { - -// identity is an extension: it is not part of the standard. -template -struct _Identity -{ - const _Tp& operator()(const _Tp& __x) const { return __x; } -}; - -// Forward declaration of equality operator; needed for friend declaration. - -template , - class _EqualKey = std::equal_to<_Value>, - class _Alloc = std::allocator > -class hash_set; - -template -bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2); - -template -class hash_set -{ -private: - typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey, - _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::const_pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::const_reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::const_iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_set() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_set(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_set(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_set(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template - hash_set(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_set(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_set(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_set(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_unique(__f, __l); - } - -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 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(__p.first, __p.second); - } - template - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_unique(__f, __l); - } - std::pair 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(__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 equal_range(const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template -bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return __hs1._M_ht == __hs2._M_ht; -} - -template -inline bool operator!=( - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return !(__hs1 == __hs2); -} - -template -inline void swap(hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - __hs1.swap(__hs2); -} - -template , - class _EqualKey = std::equal_to<_Value>, - class _Alloc = std::allocator > -class hash_multiset; - -template -bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2); - -template -class hash_multiset -{ -private: - typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey, - _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::const_pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::const_reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::const_iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_multiset() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_multiset(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_multiset(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_multiset(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template - hash_multiset(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_equal(__f, __l); - } - -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 - 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 equal_range(const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template -bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return __hs1._M_ht == __hs2._M_ht; -} - -template -inline bool operator!=( - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return !(__hs1 == __hs2); -} - -template -inline void swap(hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - __hs1.swap(__hs2); -} - -} // namespace @KWSYS_NAMESPACE@ - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -#pragma reset woff 1174 -#pragma reset woff 1375 -#endif - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/hashtable.hxx.in b/thirdparty/KWSys/adios2sys/hashtable.hxx.in deleted file mode 100644 index e962f17a99..0000000000 --- a/thirdparty/KWSys/adios2sys/hashtable.hxx.in +++ /dev/null @@ -1,992 +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 // lower_bound -#include // iterator_traits -#include // allocator -#include // size_t -#include // pair -#include // 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 -struct _Hashtable_node -{ - _Hashtable_node* _M_next; - _Val _M_val; - void public_method_to_quiet_warning_about_all_methods_private(); - -private: - void operator=(_Hashtable_node<_Val> const&); // poison node assignment -}; - -template > -class hashtable; - -template -struct _Hashtable_iterator; - -template -struct _Hashtable_const_iterator; - -template -struct _Hashtable_iterator -{ - typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> - _Hashtable; - typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, - _Alloc> - iterator; - typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc> - const_iterator; - typedef _Hashtable_node<_Val> _Node; - - typedef 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 -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 hashtable; - -template -bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2); - -// Hashtables handle allocators a bit differently than other containers -// do. If we're using standard-conforming allocators, then a hashtable -// unconditionally has a member variable to hold its allocator, even if -// it so happens that all instances of the allocator type are identical. -// This is because, for hashtables, this extra storage is negligible. -// Additionally, a base class wouldn't serve any other purposes; it -// wouldn't, for example, simplify the exception-handling code. - -template -class hashtable -{ -public: - typedef _Key key_type; - typedef _Val value_type; - typedef _HashFcn hasher; - typedef _EqualKey key_equal; - - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - - hasher hash_funct() const { return _M_hash; } - key_equal key_eq() const { return _M_equals; } - -private: - typedef _Hashtable_node<_Val> _Node; - -public: - typedef typename _Alloc::template rebind<_Val>::other allocator_type; - allocator_type get_allocator() const { return _M_node_allocator; } -private: - typedef - typename _Alloc::template rebind<_Node>::other _M_node_allocator_type; - typedef - typename _Alloc::template rebind<_Node*>::other _M_node_ptr_allocator_type; - typedef std::vector<_Node*, _M_node_ptr_allocator_type> _M_buckets_type; - -private: - _M_node_allocator_type _M_node_allocator; - hasher _M_hash; - key_equal _M_equals; - _ExtractKey _M_get_key; - _M_buckets_type _M_buckets; - size_type _M_num_elements; - - _Node* _M_get_node() { return _M_node_allocator.allocate(1); } - void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); } - -public: - typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, - _Alloc> - iterator; - typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc> - const_iterator; - - friend struct _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc>; - friend struct _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc>; - -public: - hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql, - const _ExtractKey& __ext, - const allocator_type& __a = allocator_type()) - : _M_node_allocator(__a) - , _M_hash(__hf) - , _M_equals(__eql) - , _M_get_key(__ext) - , _M_buckets(__a) - , _M_num_elements(0) - { - _M_initialize_buckets(__n); - } - - hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql, - const allocator_type& __a = allocator_type()) - : _M_node_allocator(__a) - , _M_hash(__hf) - , _M_equals(__eql) - , _M_get_key(_ExtractKey()) - , _M_buckets(__a) - , _M_num_elements(0) - { - _M_initialize_buckets(__n); - } - - hashtable(const hashtable& __ht) - : _M_node_allocator(__ht.get_allocator()) - , _M_hash(__ht._M_hash) - , _M_equals(__ht._M_equals) - , _M_get_key(__ht._M_get_key) - , _M_buckets(__ht.get_allocator()) - , _M_num_elements(0) - { - _M_copy_from(__ht); - } - - hashtable& operator=(const hashtable& __ht) - { - if (&__ht != this) { - clear(); - _M_hash = __ht._M_hash; - _M_equals = __ht._M_equals; - _M_get_key = __ht._M_get_key; - _M_copy_from(__ht); - } - return *this; - } - - ~hashtable() { clear(); } - - size_type size() const { return _M_num_elements; } - size_type max_size() const { return size_type(-1); } - bool empty() const { return size() == 0; } - - void swap(hashtable& __ht) - { - std::swap(_M_hash, __ht._M_hash); - std::swap(_M_equals, __ht._M_equals); - std::swap(_M_get_key, __ht._M_get_key); - _M_buckets.swap(__ht._M_buckets); - std::swap(_M_num_elements, __ht._M_num_elements); - } - - iterator begin() - { - for (size_type __n = 0; __n < _M_buckets.size(); ++__n) - if (_M_buckets[__n]) - return iterator(_M_buckets[__n], this); - return end(); - } - - iterator end() { return iterator(0, this); } - - const_iterator begin() const - { - for (size_type __n = 0; __n < _M_buckets.size(); ++__n) - if (_M_buckets[__n]) - return const_iterator(_M_buckets[__n], this); - return end(); - } - - const_iterator end() const { return const_iterator(0, this); } - - friend bool operator==<>(const hashtable&, const hashtable&); - -public: - size_type bucket_count() const { return _M_buckets.size(); } - - size_type max_bucket_count() const - { - return get_stl_prime_list()[(int)_stl_num_primes - 1]; - } - - size_type elems_in_bucket(size_type __bucket) const - { - size_type __result = 0; - for (_Node* __cur = _M_buckets[__bucket]; __cur; __cur = __cur->_M_next) - __result += 1; - return __result; - } - - std::pair 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 insert_unique_noresize(const value_type& __obj); - iterator insert_equal_noresize(const value_type& __obj); - - template - void insert_unique(_InputIterator __f, _InputIterator __l) - { - insert_unique( - __f, __l, - typename std::iterator_traits<_InputIterator>::iterator_category()); - } - - template - void insert_equal(_InputIterator __f, _InputIterator __l) - { - insert_equal( - __f, __l, - typename std::iterator_traits<_InputIterator>::iterator_category()); - } - - template - void insert_unique(_InputIterator __f, _InputIterator __l, - std::input_iterator_tag) - { - for (; __f != __l; ++__f) - insert_unique(*__f); - } - - template - void insert_equal(_InputIterator __f, _InputIterator __l, - std::input_iterator_tag) - { - for (; __f != __l; ++__f) - insert_equal(*__f); - } - - template - 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 - 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 equal_range(const key_type& __key); - - std::pair equal_range( - const key_type& __key) const; - - size_type erase(const key_type& __key); - void erase(const iterator& __it); - void erase(iterator __first, iterator __last); - - void erase(const const_iterator& __it); - void erase(const_iterator __first, const_iterator __last); - - void resize(size_type __num_elements_hint); - void clear(); - -private: - size_type _M_next_size(size_type __n) const { return _stl_next_prime(__n); } - - void _M_initialize_buckets(size_type __n) - { - const size_type __n_buckets = _M_next_size(__n); - _M_buckets.reserve(__n_buckets); - _M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*)0); - _M_num_elements = 0; - } - - size_type _M_bkt_num_key(const key_type& __key) const - { - return _M_bkt_num_key(__key, _M_buckets.size()); - } - - size_type _M_bkt_num(const value_type& __obj) const - { - return _M_bkt_num_key(_M_get_key(__obj)); - } - - size_type _M_bkt_num_key(const key_type& __key, size_t __n) const - { - return _M_hash(__key) % __n; - } - - size_type _M_bkt_num(const value_type& __obj, size_t __n) const - { - return _M_bkt_num_key(_M_get_key(__obj), __n); - } - - void construct(_Val* p, const _Val& v) { new (p) _Val(v); } - void destroy(_Val* p) - { - (void)p; - p->~_Val(); - } - - _Node* _M_new_node(const value_type& __obj) - { - _Node* __n = _M_get_node(); - __n->_M_next = 0; - try { - construct(&__n->_M_val, __obj); - return __n; - } catch (...) { - _M_put_node(__n); - throw; - } - } - - void _M_delete_node(_Node* __n) - { - destroy(&__n->_M_val); - _M_put_node(__n); - } - - void _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last); - void _M_erase_bucket(const size_type __n, _Node* __last); - - void _M_copy_from(const hashtable& __ht); -}; - -template -_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& - _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++() -{ - const _Node* __old = _M_cur; - _M_cur = _M_cur->_M_next; - if (!_M_cur) { - size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); - while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) - _M_cur = _M_ht->_M_buckets[__bucket]; - } - return *this; -} - -template -inline _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> - _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int) -{ - iterator __tmp = *this; - ++*this; - return __tmp; -} - -template -_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& - _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++() -{ - const _Node* __old = _M_cur; - _M_cur = _M_cur->_M_next; - if (!_M_cur) { - size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); - while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) - _M_cur = _M_ht->_M_buckets[__bucket]; - } - return *this; -} - -template -inline _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> - _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int) -{ - const_iterator __tmp = *this; - ++*this; - return __tmp; -} - -template -bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) -{ - typedef typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_Node _Node; - if (__ht1._M_buckets.size() != __ht2._M_buckets.size()) - return false; - for (int __n = 0; __n < __ht1._M_buckets.size(); ++__n) { - _Node* __cur1 = __ht1._M_buckets[__n]; - _Node* __cur2 = __ht2._M_buckets[__n]; - for (; __cur1 && __cur2 && __cur1->_M_val == __cur2->_M_val; - __cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next) { - } - if (__cur1 || __cur2) - return false; - } - return true; -} - -template -inline bool operator!=(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) -{ - return !(__ht1 == __ht2); -} - -template -inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1, - hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2) -{ - __ht1.swap(__ht2); -} - -template -std::pair::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(__cur, this), false); - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return std::pair(iterator(__tmp, this), true); -} - -template -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_equal_noresize( - const value_type& __obj) -{ - const size_type __n = _M_bkt_num(__obj); - _Node* __first = _M_buckets[__n]; - - for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) { - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __cur->_M_next; - __cur->_M_next = __tmp; - ++_M_num_elements; - return iterator(__tmp, this); - } - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return iterator(__tmp, this); -} - -template -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::reference hashtable< - _Val, _Key, _HF, _Ex, _Eq, _All>::find_or_insert(const value_type& __obj) -{ - resize(_M_num_elements + 1); - - size_type __n = _M_bkt_num(__obj); - _Node* __first = _M_buckets[__n]; - - for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) - return __cur->_M_val; - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return __tmp->_M_val; -} - -template -std::pair::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 _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 -std::pair::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 _Pii; - const size_type __n = _M_bkt_num_key(__key); - - for (const _Node* __first = _M_buckets[__n]; __first; - __first = __first->_M_next) { - if (_M_equals(_M_get_key(__first->_M_val), __key)) { - for (const _Node* __cur = __first->_M_next; __cur; - __cur = __cur->_M_next) - if (!_M_equals(_M_get_key(__cur->_M_val), __key)) - return _Pii(const_iterator(__first, this), - const_iterator(__cur, this)); - for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) - if (_M_buckets[__m]) - return _Pii(const_iterator(__first, this), - const_iterator(_M_buckets[__m], this)); - return _Pii(const_iterator(__first, this), end()); - } - } - return _Pii(end(), end()); -} - -template -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::size_type -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const key_type& __key) -{ - const size_type __n = _M_bkt_num_key(__key); - _Node* __first = _M_buckets[__n]; - size_type __erased = 0; - - if (__first) { - _Node* __cur = __first; - _Node* __next = __cur->_M_next; - while (__next) { - if (_M_equals(_M_get_key(__next->_M_val), __key)) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - __next = __cur->_M_next; - ++__erased; - --_M_num_elements; - } else { - __cur = __next; - __next = __cur->_M_next; - } - } - if (_M_equals(_M_get_key(__first->_M_val), __key)) { - _M_buckets[__n] = __first->_M_next; - _M_delete_node(__first); - ++__erased; - --_M_num_elements; - } - } - return __erased; -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const iterator& __it) -{ - _Node* __p = __it._M_cur; - if (__p) { - const size_type __n = _M_bkt_num(__p->_M_val); - _Node* __cur = _M_buckets[__n]; - - if (__cur == __p) { - _M_buckets[__n] = __cur->_M_next; - _M_delete_node(__cur); - --_M_num_elements; - } else { - _Node* __next = __cur->_M_next; - while (__next) { - if (__next == __p) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - --_M_num_elements; - break; - } else { - __cur = __next; - __next = __cur->_M_next; - } - } - } - } -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(iterator __first, - iterator __last) -{ - size_type __f_bucket = - __first._M_cur ? _M_bkt_num(__first._M_cur->_M_val) : _M_buckets.size(); - size_type __l_bucket = - __last._M_cur ? _M_bkt_num(__last._M_cur->_M_val) : _M_buckets.size(); - - if (__first._M_cur == __last._M_cur) - return; - else if (__f_bucket == __l_bucket) - _M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur); - else { - _M_erase_bucket(__f_bucket, __first._M_cur, 0); - for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n) - _M_erase_bucket(__n, 0); - if (__l_bucket != _M_buckets.size()) - _M_erase_bucket(__l_bucket, __last._M_cur); - } -} - -template -inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase( - const_iterator __first, const_iterator __last) -{ - erase(iterator(const_cast<_Node*>(__first._M_cur), - const_cast(__first._M_ht)), - iterator(const_cast<_Node*>(__last._M_cur), - const_cast(__last._M_ht))); -} - -template -inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase( - const const_iterator& __it) -{ - erase(iterator(const_cast<_Node*>(__it._M_cur), - const_cast(__it._M_ht))); -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::resize( - size_type __num_elements_hint) -{ - const size_type __old_n = _M_buckets.size(); - if (__num_elements_hint > __old_n) { - const size_type __n = _M_next_size(__num_elements_hint); - if (__n > __old_n) { - _M_buckets_type __tmp(__n, (_Node*)(0), _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 -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket( - const size_type __n, _Node* __first, _Node* __last) -{ - _Node* __cur = _M_buckets[__n]; - if (__cur == __first) - _M_erase_bucket(__n, __last); - else { - _Node* __next; - for (__next = __cur->_M_next; __next != __first; - __cur = __next, __next = __cur->_M_next) - ; - while (__next != __last) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - __next = __cur->_M_next; - --_M_num_elements; - } - } -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket( - const size_type __n, _Node* __last) -{ - _Node* __cur = _M_buckets[__n]; - while (__cur != __last) { - _Node* __next = __cur->_M_next; - _M_delete_node(__cur); - __cur = __next; - _M_buckets[__n] = __cur; - --_M_num_elements; - } -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::clear() -{ - for (size_type __i = 0; __i < _M_buckets.size(); ++__i) { - _Node* __cur = _M_buckets[__i]; - while (__cur != 0) { - _Node* __next = __cur->_M_next; - _M_delete_node(__cur); - __cur = __next; - } - _M_buckets[__i] = 0; - } - _M_num_elements = 0; -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_copy_from( - const hashtable& __ht) -{ - _M_buckets.clear(); - _M_buckets.reserve(__ht._M_buckets.size()); - _M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*)0); - try { - for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) { - const _Node* __cur = __ht._M_buckets[__i]; - if (__cur) { - _Node* __copy = _M_new_node(__cur->_M_val); - _M_buckets[__i] = __copy; - - for (_Node *__next = __cur->_M_next; __next; - __cur = __next, __next = __cur->_M_next) { - __copy->_M_next = _M_new_node(__next->_M_val); - __copy = __copy->_M_next; - } - } - } - _M_num_elements = __ht._M_num_elements; - } catch (...) { - clear(); - throw; - } -} - -} // namespace @KWSYS_NAMESPACE@ - -// Undo warning suppression. -#if defined(__clang__) && defined(__has_warning) -#if __has_warning("-Wdeprecated") -#pragma clang diagnostic pop -#endif -#endif - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#endif diff --git a/thirdparty/KWSys/adios2sys/kwsysHeaderDump.pl b/thirdparty/KWSys/adios2sys/kwsysHeaderDump.pl deleted file mode 100755 index e3391e7623..0000000000 --- a/thirdparty/KWSys/adios2sys/kwsysHeaderDump.pl +++ /dev/null @@ -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
\n"; - exit(1); -} - -$name = $ARGV[0]; -$max = 0; -open(INFILE, $ARGV[1]); -while (chomp ($line = )) -{ - if (($line !~ /^\#/) && - ($line =~ s/.*kwsys${name}_([A-Za-z0-9_]*).*/\1/) && - ($i{$line}++ < 1)) - { - push(@lines, "$line"); - if (length($line) > $max) - { - $max = length($line); - } - } -} -close(INFILE); - -$width = $max + 13; -print sprintf("#define %-${width}s kwsys_ns(${name})\n", "kwsys${name}"); -foreach $l (@lines) -{ - print sprintf("#define %-${width}s kwsys_ns(${name}_$l)\n", - "kwsys${name}_$l"); -} -print "\n"; -print sprintf("# undef kwsys${name}\n"); -foreach $l (@lines) -{ - print sprintf("# undef kwsys${name}_$l\n"); -} diff --git a/thirdparty/KWSys/adios2sys/kwsysPlatformTests.cmake b/thirdparty/KWSys/adios2sys/kwsysPlatformTests.cmake deleted file mode 100644 index 5386a49a33..0000000000 --- a/thirdparty/KWSys/adios2sys/kwsysPlatformTests.cmake +++ /dev/null @@ -1,211 +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}") - TRY_COMPILE(${var}_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} - COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} - CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}" - OUTPUT_VARIABLE OUTPUT) - IF(${var}_COMPILED) - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - ENDIF() - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - no") - ELSE() - MESSAGE(STATUS "${description} - yes") - ENDIF() - ELSE() - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - yes") - ELSE() - MESSAGE(STATUS "${description} - no") - ENDIF() - ENDIF() - ENDIF() - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - SET(${var} 0) - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - IF(${var}_COMPILED) - SET(${var} 1) - ELSE() - SET(${var} 0) - ENDIF() - ENDIF() -ENDMACRO() - -MACRO(KWSYS_PLATFORM_TEST_RUN lang var description invert) - IF(NOT DEFINED ${var}) - MESSAGE(STATUS "${description}") - TRY_RUN(${var} ${var}_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} - COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} - OUTPUT_VARIABLE OUTPUT) - - # Note that ${var} will be a 0 return value on success. - IF(${var}_COMPILED) - IF(${var}) - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled and ran with the following output:\n${OUTPUT}\n\n") - ENDIF() - ELSE() - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - SET(${var} -1 CACHE INTERNAL "${description} failed to compile.") - ENDIF() - - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - IF(${var}) - MESSAGE(STATUS "${description} - yes") - ELSE() - MESSAGE(STATUS "${description} - no") - ENDIF() - ELSE() - MESSAGE(STATUS "${description} - failed to compile") - ENDIF() - ELSE() - IF(${var}_COMPILED) - IF(${var}) - MESSAGE(STATUS "${description} - no") - ELSE() - MESSAGE(STATUS "${description} - yes") - ENDIF() - ELSE() - MESSAGE(STATUS "${description} - failed to compile") - ENDIF() - ENDIF() - ENDIF() - - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - IF(${var}) - SET(${var} 1) - ELSE() - SET(${var} 0) - ENDIF() - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - IF(${var}_COMPILED) - IF(${var}) - SET(${var} 0) - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - SET(${var} 0) - ENDIF() - ENDIF() -ENDMACRO() - -MACRO(KWSYS_PLATFORM_C_TEST var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) - KWSYS_PLATFORM_TEST(C "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() - -MACRO(KWSYS_PLATFORM_C_TEST_RUN var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) - KWSYS_PLATFORM_TEST_RUN(C "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() - -MACRO(KWSYS_PLATFORM_CXX_TEST var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) - SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES}) - KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) - SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES) -ENDMACRO() - -MACRO(KWSYS_PLATFORM_CXX_TEST_RUN var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) - KWSYS_PLATFORM_TEST_RUN(CXX "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() - -#----------------------------------------------------------------------------- -# KWSYS_PLATFORM_INFO_TEST(lang var description) -# -# Compile test named by ${var} and store INFO strings extracted from binary. -MACRO(KWSYS_PLATFORM_INFO_TEST lang var description) - # We can implement this macro on CMake 2.6 and above. - IF("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6) - SET(${var} "") - ELSE() - # Choose a location for the result binary. - SET(KWSYS_PLATFORM_INFO_FILE - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${var}.bin) - - # Compile the test binary. - IF(NOT EXISTS ${KWSYS_PLATFORM_INFO_FILE}) - MESSAGE(STATUS "${description}") - TRY_COMPILE(${var}_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} - COMPILE_DEFINITIONS -DTEST_${var} - ${KWSYS_PLATFORM_${lang}_TEST_DEFINES} - ${KWSYS_PLATFORM_${lang}_TEST_EXTRA_FLAGS} - OUTPUT_VARIABLE OUTPUT - COPY_FILE ${KWSYS_PLATFORM_INFO_FILE} - ) - IF(${var}_COMPILED) - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - ENDIF() - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - compiled") - ELSE() - MESSAGE(STATUS "${description} - failed") - ENDIF() - ENDIF() - - # Parse info strings out of the compiled binary. - IF(${var}_COMPILED) - FILE(STRINGS ${KWSYS_PLATFORM_INFO_FILE} ${var} REGEX "INFO:[A-Za-z0-9]+\\[[^]]*\\]") - ELSE() - SET(${var} "") - ENDIF() - - SET(KWSYS_PLATFORM_INFO_FILE) - ENDIF() -ENDMACRO() diff --git a/thirdparty/KWSys/adios2sys/kwsysPlatformTestsC.c b/thirdparty/KWSys/adios2sys/kwsysPlatformTestsC.c deleted file mode 100644 index 5432633eb8..0000000000 --- a/thirdparty/KWSys/adios2sys/kwsysPlatformTestsC.c +++ /dev/null @@ -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 -int f(ptrdiff_t n) -{ - return n > 0; -} -int KWSYS_PLATFORM_TEST_C_MAIN() -{ - char* p = 0; - ptrdiff_t d = p - p; - (void)d; - return f(p - p); -} -#endif - -#ifdef TEST_KWSYS_C_HAS_SSIZE_T -#include -int f(ssize_t n) -{ - return (int)n; -} -int KWSYS_PLATFORM_TEST_C_MAIN() -{ - ssize_t n = 0; - return f(n); -} -#endif - -#ifdef TEST_KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC -#if defined(__APPLE__) -#include -#if MAC_OS_X_VERSION_MIN_REQUIRED < 101200 -#error "clock_gettime not available on macOS < 10.12" -#endif -#endif -#include -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 diff --git a/thirdparty/KWSys/adios2sys/kwsysPlatformTestsCXX.cxx b/thirdparty/KWSys/adios2sys/kwsysPlatformTestsCXX.cxx deleted file mode 100644 index f1f9ed351b..0000000000 --- a/thirdparty/KWSys/adios2sys/kwsysPlatformTestsCXX.cxx +++ /dev/null @@ -1,377 +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 -int main() -{ - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_LONG_LONG -long long f(long long n) -{ - return n; -} -int main() -{ - long long n = 0; - return static_cast(f(n)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS___INT64 -__int64 f(__int64 n) -{ - return n; -} -int main() -{ - __int64 n = 0; - return static_cast(f(n)); -} -#endif - -#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIM -#include - -#include -#include -int main() -{ - struct stat stat1; - (void)stat1.st_mtim.tv_sec; - (void)stat1.st_mtim.tv_nsec; - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIMESPEC -#include - -#include -#include -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 -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 -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 -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 -int test_ostream(std::ostream& os, __int64 x) -{ - return (os << x) ? 1 : 0; -} -int main() -{ - __int64 x = 0; - return test_ostream(std::cout, x); -} -#endif - -#ifdef TEST_KWSYS_LFS_WORKS -/* Return 0 when LFS is available and 1 otherwise. */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#define _LARGE_FILES -#define _FILE_OFFSET_BITS 64 -#include - -#include -#include -#if KWSYS_CXX_HAS_CSTDIO -#include -#endif -#include - -int main(int, char** argv) -{ -/* check that off_t can hold 2^63 - 1 and perform basic operations... */ -#define OFF_T_64 (((off_t)1 << 62) - 1 + ((off_t)1 << 62)) - if (OFF_T_64 % 2147483647 != 1) - return 1; - - // stat breaks on SCO OpenServer - struct stat buf; - stat(argv[0], &buf); - if (!S_ISREG(buf.st_mode)) - return 2; - - FILE* file = fopen(argv[0], "r"); - off_t offset = ftello(file); - fseek(file, offset, SEEK_CUR); - fclose(file); - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_SETENV -#include -int main() -{ - return setenv("A", "B", 1); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_UNSETENV -#include -int main() -{ - unsetenv("A"); - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H -#include -int main() -{ - char* e = environ[0]; - return e ? 0 : 1; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_GETLOADAVG -// Match feature definitions from SystemInformation.cxx -#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) -#define _GNU_SOURCE -#endif -#include -int main() -{ - double loadavg[3] = { 0.0, 0.0, 0.0 }; - return getloadavg(loadavg, 3); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64 -#if defined(KWSYS_HAS_LFS) -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#define _LARGE_FILES -#define _FILE_OFFSET_BITS 64 -#endif -#include -int main() -{ - struct rlimit64 rlim; - return getrlimit64(0, &rlim); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_ATOLL -#include -int main() -{ - const char* str = "1024"; - return static_cast(atoll(str)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_ATOL -#include -int main() -{ - const char* str = "1024"; - return static_cast(atol(str)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS__ATOI64 -#include -int main() -{ - const char* str = "1024"; - return static_cast(_atoi64(str)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_UTIMES -#include -int main() -{ - struct timeval* current_time = 0; - return utimes("/example", current_time); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_UTIMENSAT -#include -#include -#if defined(__APPLE__) -#include -#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 -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 -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 -#endif -#include -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 -void f(std::wstring*) -{ -} -int main() -{ - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H -#include -int main() -{ - return 0; -} -#endif diff --git a/thirdparty/KWSys/adios2sys/kwsysPrivate.h b/thirdparty/KWSys/adios2sys/kwsysPrivate.h deleted file mode 100644 index ce1b53ed85..0000000000 --- a/thirdparty/KWSys/adios2sys/kwsysPrivate.h +++ /dev/null @@ -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) - -/* - Define KWSYS_NAMESPACE_STRING to be a string constant containing the - name configured for this instance of the kwsys library. -*/ -#define KWSYS_NAMESPACE_STRING KWSYS_NAMESPACE_STRING0(KWSYS_NAMESPACE) -#define KWSYS_NAMESPACE_STRING0(x) KWSYS_NAMESPACE_STRING1(x) -#define KWSYS_NAMESPACE_STRING1(x) #x - -#else -#error "kwsysPrivate.h included multiple times." -#endif diff --git a/thirdparty/KWSys/adios2sys/testCommandLineArguments.cxx b/thirdparty/KWSys/adios2sys/testCommandLineArguments.cxx deleted file mode 100644 index 78baed97af..0000000000 --- a/thirdparty/KWSys/adios2sys/testCommandLineArguments.cxx +++ /dev/null @@ -1,208 +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 -#include - -#include /* size_t */ -#include /* strcmp */ - -static void* random_ptr = reinterpret_cast(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 = KWSYS_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 numbers_argument; - int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 }; - - std::vector doubles_argument; - double valid_doubles[] = { 12.5, 1.31, 22 }; - - std::vector bools_argument; - bool valid_bools[] = { true, true, false }; - - std::vector strings_argument; - const char* valid_strings[] = { "andy", "bill", "brad", "ken" }; - - std::vector stl_strings_argument; - std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" }; - - typedef kwsys::CommandLineArguments argT; - - arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT, - &some_int_variable, "Set some random int variable"); - arg.AddArgument("--some-double-variable", argT::CONCAT_ARGUMENT, - &some_double_variable, "Set some random double variable"); - arg.AddArgument("--some-string-variable", argT::EQUAL_ARGUMENT, - &some_string_variable, "Set some random string variable"); - arg.AddArgument("--some-stl-string-variable", argT::EQUAL_ARGUMENT, - &some_stl_string_variable, - "Set some random stl string variable"); - arg.AddArgument("--some-bool-variable", argT::EQUAL_ARGUMENT, - &some_bool_variable, "Set some random bool variable"); - arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT, - &some_bool_variable1, "Set some random bool variable 1"); - arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1, - "Test AddBooleanArgument 1"); - arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2, - "Test AddBooleanArgument 2"); - arg.AddArgument("--some-multi-argument", argT::MULTI_ARGUMENT, - &numbers_argument, "Some multiple values variable"); - arg.AddArgument("-N", argT::SPACE_ARGUMENT, &doubles_argument, - "Some explicit multiple values variable"); - arg.AddArgument("-BB", argT::CONCAT_ARGUMENT, &bools_argument, - "Some explicit multiple values variable"); - arg.AddArgument("-SS", argT::EQUAL_ARGUMENT, &strings_argument, - "Some explicit multiple values variable"); - arg.AddArgument("-SSS", argT::MULTI_ARGUMENT, &stl_strings_argument, - "Some explicit multiple values variable"); - - arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr, - "Some option -A. This option has a multiline comment. It " - "should demonstrate how the code splits lines."); - arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr, - "Option -B takes argument with space"); - arg.AddCallback("-C", argT::EQUAL_ARGUMENT, argument, random_ptr, - "Option -C takes argument after ="); - arg.AddCallback("-D", argT::CONCAT_ARGUMENT, argument, random_ptr, - "This option takes concatinated argument"); - arg.AddCallback("--long1", argT::NO_ARGUMENT, argument, random_ptr, "-A"); - arg.AddCallback("--long2", argT::SPACE_ARGUMENT, argument, random_ptr, "-B"); - arg.AddCallback("--long3", argT::EQUAL_ARGUMENT, argument, random_ptr, - "Same as -C but a bit different"); - arg.AddCallback("--long4", argT::CONCAT_ARGUMENT, argument, random_ptr, - "-C"); - - if (!arg.Parse()) { - std::cerr << "Problem parsing arguments" << std::endl; - res = 1; - } - std::cout << "Help: " << arg.GetHelp() << std::endl; - - std::cout << "Some int variable was set to: " << some_int_variable - << std::endl; - std::cout << "Some double variable was set to: " << some_double_variable - << std::endl; - if (some_string_variable && - strcmp(some_string_variable, "test string with space") == 0) { - std::cout << "Some string variable was set to: " << some_string_variable - << std::endl; - delete[] some_string_variable; - } else { - std::cerr << "Problem setting string variable" << std::endl; - res = 1; - } - size_t cc; -#define CompareTwoLists(list1, list_valid, lsize) \ - if (list1.size() != lsize) { \ - std::cerr << "Problem setting " #list1 ". Size is: " << list1.size() \ - << " should be: " << lsize << std::endl; \ - res = 1; \ - } else { \ - std::cout << #list1 " argument set:"; \ - for (cc = 0; cc < lsize; ++cc) { \ - std::cout << " " << list1[cc]; \ - if (!CompareTwoItemsOnList(list1[cc], list_valid[cc])) { \ - std::cerr << "Problem setting " #list1 ". Value of " << cc \ - << " is: [" << list1[cc] << "] <> [" << list_valid[cc] \ - << "]" << std::endl; \ - res = 1; \ - break; \ - } \ - } \ - std::cout << std::endl; \ - } - - CompareTwoLists(numbers_argument, valid_numbers, 10); - CompareTwoLists(doubles_argument, valid_doubles, 3); - CompareTwoLists(bools_argument, valid_bools, 3); - CompareTwoLists(strings_argument, valid_strings, 4); - CompareTwoLists(stl_strings_argument, valid_stl_strings, 4); - - std::cout << "Some STL String variable was set to: " - << some_stl_string_variable << std::endl; - std::cout << "Some bool variable was set to: " << some_bool_variable - << std::endl; - std::cout << "Some bool variable was set to: " << some_bool_variable1 - << std::endl; - std::cout << "bool_arg1 variable was set to: " << bool_arg1 << std::endl; - std::cout << "bool_arg2 variable was set to: " << bool_arg2 << std::endl; - std::cout << std::endl; - - for (cc = 0; cc < strings_argument.size(); ++cc) { - delete[] strings_argument[cc]; - strings_argument[cc] = KWSYS_NULLPTR; - } - return res; -} diff --git a/thirdparty/KWSys/adios2sys/testCommandLineArguments1.cxx b/thirdparty/KWSys/adios2sys/testCommandLineArguments1.cxx deleted file mode 100644 index 5dfa5e3f3a..0000000000 --- a/thirdparty/KWSys/adios2sys/testCommandLineArguments1.cxx +++ /dev/null @@ -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 -#include - -#include /* assert */ -#include /* strcmp */ - -int testCommandLineArguments1(int argc, char* argv[]) -{ - kwsys::CommandLineArguments arg; - arg.Initialize(argc, argv); - - int n = 0; - char* m = KWSYS_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 = KWSYS_NULLPTR; - int newArgc = 0; - arg.GetUnusedArguments(&newArgc, &newArgv); - int cc; - const char* valid_unused_args[9] = { KWSYS_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; -} diff --git a/thirdparty/KWSys/adios2sys/testConfigure.cxx b/thirdparty/KWSys/adios2sys/testConfigure.cxx deleted file mode 100644 index 916dcc1351..0000000000 --- a/thirdparty/KWSys/adios2sys/testConfigure.cxx +++ /dev/null @@ -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; -} diff --git a/thirdparty/KWSys/adios2sys/testConsoleBuf.cxx b/thirdparty/KWSys/adios2sys/testConsoleBuf.cxx deleted file mode 100644 index 816a4338e6..0000000000 --- a/thirdparty/KWSys/adios2sys/testConsoleBuf.cxx +++ /dev/null @@ -1,773 +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 -#include -#include -#include -#include -#include -#include - -#include "testConsoleBuf.hxx" - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#define KWSYS_WINDOWS_DEPRECATED_GetVersion -#endif -// يونيكود -static const WCHAR UnicodeInputTestString[] = - L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!"; -static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE; - -static const DWORD waitTimeout = 10 * 1000; -static STARTUPINFO startupInfo; -static PROCESS_INFORMATION processInfo; -static HANDLE beforeInputEvent; -static HANDLE afterOutputEvent; -static std::string encodedInputTestString; -static std::string encodedTestString; - -static void displayError(DWORD errorCode) -{ - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "Failed with error: 0x" << errorCode << "!" << std::endl; - LPWSTR message; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, errorCode, 0, (LPWSTR)&message, 0, NULL)) { - std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message) - << std::endl; - HeapFree(GetProcessHeap(), 0, message); - } else { - std::cerr << "FormatMessage() failed with error: 0x" << GetLastError() - << "!" << std::endl; - } - std::cerr.unsetf(std::ios::hex); -} - -std::basic_streambuf* errstream(const char* unused) -{ - static_cast(unused); - return std::cerr.rdbuf(); -} - -std::basic_streambuf* errstream(const wchar_t* unused) -{ - static_cast(unused); - return std::wcerr.rdbuf(); -} - -template -static void dumpBuffers(const T* expected, const T* received, size_t size) -{ - std::basic_ostream err(errstream(expected)); - err << "Expected output: '" << std::basic_string(expected, size) << "'" - << std::endl; - if (err.fail()) { - err.clear(); - err << "--- Error while outputting ---" << std::endl; - } - err << "Received output: '" << std::basic_string(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(expected[i]) - << " | " - << "0x" << std::setw(8) - << static_cast(received[i]); - if (static_cast(expected[i]) != - static_cast(received[i])) { - std::cerr << " MISMATCH!"; - } - std::cerr << std::endl; - } - std::cerr << std::endl; -} - -static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr) -{ - BOOL bInheritHandles = FALSE; - DWORD dwCreationFlags = 0; - memset(&processInfo, 0, sizeof(processInfo)); - memset(&startupInfo, 0, sizeof(startupInfo)); - startupInfo.cb = sizeof(startupInfo); - startupInfo.dwFlags = STARTF_USESHOWWINDOW; - startupInfo.wShowWindow = SW_HIDE; - if (hIn || hOut || hErr) { - startupInfo.dwFlags |= STARTF_USESTDHANDLES; - startupInfo.hStdInput = hIn; - startupInfo.hStdOutput = hOut; - startupInfo.hStdError = hErr; - bInheritHandles = TRUE; - } - - WCHAR cmd[MAX_PATH]; - if (GetModuleFileNameW(NULL, cmd, MAX_PATH) == 0) { - std::cerr << "GetModuleFileName failed!" << std::endl; - return false; - } - WCHAR* p = cmd + wcslen(cmd); - while (p > cmd && *p != L'\\') - p--; - *(p + 1) = 0; - wcscat(cmd, cmdConsoleBufChild); - wcscat(cmd, L".exe"); - - bool success = - CreateProcessW(NULL, // No module name (use command line) - cmd, // Command line - NULL, // Process handle not inheritable - NULL, // Thread handle not inheritable - bInheritHandles, // Set handle inheritance - dwCreationFlags, - NULL, // Use parent's environment block - NULL, // Use parent's starting directory - &startupInfo, // Pointer to STARTUPINFO structure - &processInfo) != - 0; // Pointer to PROCESS_INFORMATION structure - if (!success) { - DWORD lastError = GetLastError(); - std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) << ")" - << std::endl; - displayError(lastError); - } - return success; -} - -static void finishProcess(bool success) -{ - if (success) { - success = - WaitForSingleObject(processInfo.hProcess, waitTimeout) == WAIT_OBJECT_0; - }; - if (!success) { - TerminateProcess(processInfo.hProcess, 1); - } - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); -} - -static bool createPipe(PHANDLE readPipe, PHANDLE writePipe) -{ - SECURITY_ATTRIBUTES securityAttributes; - securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - securityAttributes.bInheritHandle = TRUE; - securityAttributes.lpSecurityDescriptor = NULL; - return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0 ? false - : true; -} - -static void finishPipe(HANDLE readPipe, HANDLE writePipe) -{ - if (readPipe != INVALID_HANDLE_VALUE) { - CloseHandle(readPipe); - } - if (writePipe != INVALID_HANDLE_VALUE) { - CloseHandle(writePipe); - } -} - -static HANDLE createFile(LPCWSTR fileName) -{ - SECURITY_ATTRIBUTES securityAttributes; - securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - securityAttributes.bInheritHandle = TRUE; - securityAttributes.lpSecurityDescriptor = NULL; - - HANDLE file = - CreateFileW(fileName, GENERIC_READ | GENERIC_WRITE, - 0, // do not share - &securityAttributes, - CREATE_ALWAYS, // overwrite existing - FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - NULL); // no template - if (file == INVALID_HANDLE_VALUE) { - DWORD lastError = GetLastError(); - std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) << ")" - << std::endl; - displayError(lastError); - } - return file; -} - -static void finishFile(HANDLE file) -{ - if (file != INVALID_HANDLE_VALUE) { - CloseHandle(file); - } -} - -#ifndef MAPVK_VK_TO_VSC -#define MAPVK_VK_TO_VSC (0) -#endif - -static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr) -{ - inputBuffer[0].EventType = KEY_EVENT; - inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE; - inputBuffer[0].Event.KeyEvent.wRepeatCount = 1; - SHORT keyCode = VkKeyScanW(chr); - if (keyCode == -1) { - // Character can't be entered with current keyboard layout - // Just set any, it doesn't really matter - keyCode = 'K'; - } - inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode); - inputBuffer[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey( - inputBuffer[0].Event.KeyEvent.wVirtualKeyCode, MAPVK_VK_TO_VSC); - inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr; - inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0; - if ((HIBYTE(keyCode) & 1) == 1) { - inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; - } - if ((HIBYTE(keyCode) & 2) == 2) { - inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED; - } - if ((HIBYTE(keyCode) & 4) == 4) { - inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED; - } - inputBuffer[1].EventType = inputBuffer[0].EventType; - inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE; - inputBuffer[1].Event.KeyEvent.wRepeatCount = 1; - inputBuffer[1].Event.KeyEvent.wVirtualKeyCode = - inputBuffer[0].Event.KeyEvent.wVirtualKeyCode; - inputBuffer[1].Event.KeyEvent.wVirtualScanCode = - inputBuffer[0].Event.KeyEvent.wVirtualScanCode; - inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar = - inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar; - inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0; -} - -static int testPipe() -{ - int didFail = 1; - HANDLE inPipeRead = INVALID_HANDLE_VALUE; - HANDLE inPipeWrite = INVALID_HANDLE_VALUE; - HANDLE outPipeRead = INVALID_HANDLE_VALUE; - HANDLE outPipeWrite = INVALID_HANDLE_VALUE; - HANDLE errPipeRead = INVALID_HANDLE_VALUE; - HANDLE errPipeWrite = INVALID_HANDLE_VALUE; - UINT currentCodepage = GetConsoleCP(); - char buffer[200]; - char buffer2[200]; - try { - if (!createPipe(&inPipeRead, &inPipeWrite) || - !createPipe(&outPipeRead, &outPipeWrite) || - !createPipe(&errPipeRead, &errPipeWrite)) { - throw std::runtime_error("createFile failed!"); - } - if (TestCodepage == CP_ACP) { - TestCodepage = GetACP(); - } - if (!SetConsoleCP(TestCodepage)) { - throw std::runtime_error("SetConsoleCP failed!"); - } - - DWORD bytesWritten = 0; - if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(), - (DWORD)encodedInputTestString.size(), &bytesWritten, - NULL) || - bytesWritten == 0) { - throw std::runtime_error("WriteFile failed!"); - } - - if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) { - try { - DWORD status; - if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != - WAIT_OBJECT_0) { - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "WaitForSingleObject returned unexpected status 0x" - << status << std::endl; - std::cerr.unsetf(std::ios::hex); - throw std::runtime_error("WaitForSingleObject failed!"); - } - DWORD bytesRead = 0; - if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, NULL) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#1 failed!"); - } - buffer[bytesRead] = 0; - if ((bytesRead < - encodedTestString.size() + 1 + encodedInputTestString.size() && - !ReadFile(outPipeRead, buffer + bytesRead, - sizeof(buffer) - bytesRead, &bytesRead, NULL)) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#2 failed!"); - } - if (memcmp(buffer, encodedTestString.c_str(), - encodedTestString.size()) == 0 && - memcmp(buffer + encodedTestString.size() + 1, - encodedInputTestString.c_str(), - encodedInputTestString.size()) == 0) { - bytesRead = 0; - if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead, - NULL) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#3 failed!"); - } - buffer2[bytesRead] = 0; - didFail = encodedTestString.compare(0, 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(encodedTestString.c_str(), buffer, - encodedTestString.size()); - dumpBuffers(encodedInputTestString.c_str(), - buffer + encodedTestString.size() + 1, - encodedInputTestString.size()); - dumpBuffers(encodedTestString.c_str(), buffer2, - encodedTestString.size()); - } - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testPipe, line " << __LINE__ << ": " - << ex.what() << std::endl; - displayError(lastError); - } - finishProcess(didFail == 0); - } - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testPipe, line " << __LINE__ << ": " << ex.what() - << std::endl; - displayError(lastError); - } - finishPipe(inPipeRead, inPipeWrite); - finishPipe(outPipeRead, outPipeWrite); - finishPipe(errPipeRead, errPipeWrite); - SetConsoleCP(currentCodepage); - return didFail; -} - -static int testFile() -{ - int didFail = 1; - HANDLE inFile = INVALID_HANDLE_VALUE; - HANDLE outFile = INVALID_HANDLE_VALUE; - HANDLE errFile = INVALID_HANDLE_VALUE; - try { - if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE || - (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE || - (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) { - throw std::runtime_error("createFile failed!"); - } - DWORD bytesWritten = 0; - char buffer[200]; - char buffer2[200]; - - int length; - if ((length = - WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1, - buffer, sizeof(buffer), NULL, NULL)) == 0) { - throw std::runtime_error("WideCharToMultiByte failed!"); - } - buffer[length - 1] = '\n'; - if (!WriteFile(inFile, buffer, length, &bytesWritten, NULL) || - bytesWritten == 0) { - throw std::runtime_error("WriteFile failed!"); - } - if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { - throw std::runtime_error("SetFilePointer failed!"); - } - - if (createProcess(inFile, outFile, errFile)) { - DWORD bytesRead = 0; - try { - DWORD status; - if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != - WAIT_OBJECT_0) { - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "WaitForSingleObject returned unexpected status 0x" - << status << std::endl; - std::cerr.unsetf(std::ios::hex); - throw std::runtime_error("WaitForSingleObject failed!"); - } - if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) == - INVALID_SET_FILE_POINTER) { - throw std::runtime_error("SetFilePointer#1 failed!"); - } - if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, NULL) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#1 failed!"); - } - buffer[bytesRead] = 0; - if (memcmp(buffer, encodedTestString.c_str(), - encodedTestString.size()) == 0 && - memcmp(buffer + encodedTestString.size() + 1, - encodedInputTestString.c_str(), - encodedInputTestString.size()) == 0) { - bytesRead = 0; - if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) == - INVALID_SET_FILE_POINTER) { - throw std::runtime_error("SetFilePointer#2 failed!"); - } - - if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, NULL) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#2 failed!"); - } - buffer2[bytesRead] = 0; - didFail = encodedTestString.compare(0, 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(encodedTestString.c_str(), buffer, - encodedTestString.size()); - dumpBuffers(encodedInputTestString.c_str(), - buffer + encodedTestString.size() + 1, - encodedInputTestString.size()); - dumpBuffers(encodedTestString.c_str(), buffer2, - encodedTestString.size()); - } - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testFile, line " << __LINE__ << ": " - << ex.what() << std::endl; - displayError(lastError); - } - finishProcess(didFail == 0); - } - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testFile, line " << __LINE__ << ": " << ex.what() - << std::endl; - displayError(lastError); - } - finishFile(inFile); - finishFile(outFile); - finishFile(errFile); - return didFail; -} - -#ifndef _WIN32_WINNT_VISTA -#define _WIN32_WINNT_VISTA 0x0600 -#endif - -static int testConsole() -{ - int didFail = 1; - HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE); - HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE); - HANDLE hIn = parentIn; - HANDLE hOut = parentOut; - DWORD consoleMode; - bool newConsole = false; - bool forceNewConsole = false; - bool restoreConsole = false; - LPCWSTR TestFaceName = L"Lucida Console"; - const DWORD TestFontFamily = 0x00000036; - const DWORD TestFontSize = 0x000c0000; - HKEY hConsoleKey; - WCHAR FaceName[200]; - FaceName[0] = 0; - DWORD FaceNameSize = sizeof(FaceName); - DWORD FontFamily = TestFontFamily; - DWORD FontSize = TestFontSize; -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion -#pragma warning(push) -#ifdef __INTEL_COMPILER -#pragma warning(disable : 1478) -#else -#pragma warning(disable : 4996) -#endif -#endif - const bool isVistaOrGreater = - LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA); -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion -#pragma warning(pop) -#endif - if (!isVistaOrGreater) { - if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE, - &hConsoleKey) == ERROR_SUCCESS) { - DWORD dwordSize = sizeof(DWORD); - if (RegQueryValueExW(hConsoleKey, L"FontFamily", NULL, NULL, - (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) { - if (FontFamily != TestFontFamily) { - RegQueryValueExW(hConsoleKey, L"FaceName", NULL, NULL, - (LPBYTE)FaceName, &FaceNameSize); - RegQueryValueExW(hConsoleKey, L"FontSize", NULL, NULL, - (LPBYTE)&FontSize, &dwordSize); - - RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, - (BYTE*)&TestFontFamily, sizeof(TestFontFamily)); - RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, - (BYTE*)TestFaceName, - (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR))); - RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, - (BYTE*)&TestFontSize, sizeof(TestFontSize)); - - restoreConsole = true; - forceNewConsole = true; - } - } else { - std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl; - } - RegCloseKey(hConsoleKey); - } else { - std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!" - << std::endl; - } - } - if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) { - // Not a real console, let's create new one. - FreeConsole(); - if (!AllocConsole()) { - std::cerr << "AllocConsole failed!" << std::endl; - return didFail; - } - SECURITY_ATTRIBUTES securityAttributes; - securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - securityAttributes.bInheritHandle = TRUE; - securityAttributes.lpSecurityDescriptor = NULL; - hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, - OPEN_EXISTING, 0, NULL); - if (hIn == INVALID_HANDLE_VALUE) { - DWORD lastError = GetLastError(); - std::cerr << "CreateFile(CONIN$)" << std::endl; - displayError(lastError); - } - hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, - OPEN_EXISTING, 0, NULL); - if (hOut == INVALID_HANDLE_VALUE) { - DWORD lastError = GetLastError(); - std::cerr << "CreateFile(CONOUT$)" << std::endl; - displayError(lastError); - } - SetStdHandle(STD_INPUT_HANDLE, hIn); - SetStdHandle(STD_OUTPUT_HANDLE, hOut); - SetStdHandle(STD_ERROR_HANDLE, hOut); - newConsole = true; - } - -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA - if (isVistaOrGreater) { - CONSOLE_FONT_INFOEX consoleFont; - memset(&consoleFont, 0, sizeof(consoleFont)); - consoleFont.cbSize = sizeof(consoleFont); - HMODULE kernel32 = LoadLibraryW(L"kernel32.dll"); - typedef BOOL(WINAPI * GetCurrentConsoleFontExFunc)( - HANDLE hConsoleOutput, BOOL bMaximumWindow, - PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); - typedef BOOL(WINAPI * SetCurrentConsoleFontExFunc)( - HANDLE hConsoleOutput, BOOL bMaximumWindow, - PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); - GetCurrentConsoleFontExFunc getConsoleFont = - (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32, - "GetCurrentConsoleFontEx"); - SetCurrentConsoleFontExFunc setConsoleFont = - (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32, - "SetCurrentConsoleFontEx"); - if (getConsoleFont(hOut, FALSE, &consoleFont)) { - if (consoleFont.FontFamily != TestFontFamily) { - consoleFont.FontFamily = TestFontFamily; - wcscpy(consoleFont.FaceName, TestFaceName); - if (!setConsoleFont(hOut, FALSE, &consoleFont)) { - std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl; - } - } - } else { - std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl; - } - } else { -#endif - if (restoreConsole && - RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_WRITE, - &hConsoleKey) == ERROR_SUCCESS) { - RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, - (BYTE*)&FontFamily, sizeof(FontFamily)); - if (FaceName[0] != 0) { - RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, (BYTE*)FaceName, - FaceNameSize); - } else { - RegDeleteValueW(hConsoleKey, L"FaceName"); - } - RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE*)&FontSize, - sizeof(FontSize)); - RegCloseKey(hConsoleKey); - } -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA - } -#endif - - if (createProcess(NULL, NULL, NULL)) { - try { - DWORD status; - if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) != - WAIT_OBJECT_0) { - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "WaitForSingleObject returned unexpected status 0x" - << status << std::endl; - std::cerr.unsetf(std::ios::hex); - throw std::runtime_error("WaitForSingleObject#1 failed!"); - } - INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) / - sizeof(UnicodeInputTestString[0])) * - 2]; - memset(&inputBuffer, 0, sizeof(inputBuffer)); - unsigned int i; - for (i = 0; i < (sizeof(UnicodeInputTestString) / - sizeof(UnicodeInputTestString[0]) - - 1); - i++) { - writeInputKeyEvent(&inputBuffer[i * 2], UnicodeInputTestString[i]); - } - writeInputKeyEvent(&inputBuffer[i * 2], VK_RETURN); - DWORD eventsWritten = 0; - // We need to wait a bit before writing to console so child process have - // started waiting for input on stdin. - Sleep(300); - if (!WriteConsoleInputW(hIn, inputBuffer, - sizeof(inputBuffer) / sizeof(inputBuffer[0]), - &eventsWritten) || - eventsWritten == 0) { - throw std::runtime_error("WriteConsoleInput failed!"); - } - if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != - WAIT_OBJECT_0) { - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "WaitForSingleObject returned unexpected status 0x" - << status << std::endl; - std::cerr.unsetf(std::ios::hex); - throw std::runtime_error("WaitForSingleObject#2 failed!"); - } - CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo; - if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) { - throw std::runtime_error("GetConsoleScreenBufferInfo failed!"); - } - - COORD coord; - DWORD charsRead = 0; - coord.X = 0; - coord.Y = screenBufferInfo.dwCursorPosition.Y - 4; - WCHAR* outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4]; - if (!ReadConsoleOutputCharacterW(hOut, outputBuffer, - screenBufferInfo.dwSize.X * 4, coord, - &charsRead) || - charsRead == 0) { - delete[] outputBuffer; - throw std::runtime_error("ReadConsoleOutputCharacter failed!"); - } - std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString); - std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' '); - std::wstring wideInputTestString = - kwsys::Encoding::ToWide(encodedInputTestString); - if (memcmp(outputBuffer, wideTestString.c_str(), - wideTestString.size() * sizeof(wchar_t)) == 0 && - memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1, - wideTestString.c_str(), - wideTestString.size() * sizeof(wchar_t)) == 0 && - memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2, - UnicodeInputTestString, - sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 && - memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3, - wideInputTestString.c_str(), - (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0) { - didFail = 0; - } else { - std::cerr << "Console's output didn't match expected output!" - << std::endl; - dumpBuffers(wideTestString.c_str(), outputBuffer, - wideTestString.size()); - dumpBuffers(wideTestString.c_str(), - outputBuffer + screenBufferInfo.dwSize.X * 1, - wideTestString.size()); - dumpBuffers( - UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2, - (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR)); - dumpBuffers(wideInputTestString.c_str(), - outputBuffer + screenBufferInfo.dwSize.X * 3, - wideInputTestString.size() - 1); - } - delete[] outputBuffer; - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testConsole, line " << __LINE__ << ": " - << ex.what() << std::endl; - displayError(lastError); - } - finishProcess(didFail == 0); - } - if (newConsole) { - SetStdHandle(STD_INPUT_HANDLE, parentIn); - SetStdHandle(STD_OUTPUT_HANDLE, parentOut); - SetStdHandle(STD_ERROR_HANDLE, parentErr); - CloseHandle(hIn); - CloseHandle(hOut); - FreeConsole(); - } - return didFail; -} - -#endif - -int testConsoleBuf(int, char* []) -{ - int ret = 0; - -#if defined(_WIN32) - beforeInputEvent = CreateEventW(NULL, - FALSE, // auto-reset event - FALSE, // initial state is nonsignaled - BeforeInputEventName); // object name - if (!beforeInputEvent) { - std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl; - return 1; - } - - afterOutputEvent = CreateEventW(NULL, FALSE, FALSE, AfterOutputEventName); - if (!afterOutputEvent) { - std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl; - return 1; - } - - encodedTestString = kwsys::Encoding::ToNarrow(std::wstring( - UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1)); - encodedInputTestString = kwsys::Encoding::ToNarrow( - std::wstring(UnicodeInputTestString, - sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1)); - encodedInputTestString += "\n"; - - ret |= testPipe(); - ret |= testFile(); - ret |= testConsole(); - - CloseHandle(beforeInputEvent); - CloseHandle(afterOutputEvent); -#endif - - return ret; -} diff --git a/thirdparty/KWSys/adios2sys/testConsoleBuf.hxx b/thirdparty/KWSys/adios2sys/testConsoleBuf.hxx deleted file mode 100644 index e93cb4f0a1..0000000000 --- a/thirdparty/KWSys/adios2sys/testConsoleBuf.hxx +++ /dev/null @@ -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 diff --git a/thirdparty/KWSys/adios2sys/testConsoleBufChild.cxx b/thirdparty/KWSys/adios2sys/testConsoleBufChild.cxx deleted file mode 100644 index 6a743edcda..0000000000 --- a/thirdparty/KWSys/adios2sys/testConsoleBufChild.cxx +++ /dev/null @@ -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 - -#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(argc); - static_cast(argv); -#endif - return 0; -} diff --git a/thirdparty/KWSys/adios2sys/testDirectory.cxx b/thirdparty/KWSys/adios2sys/testDirectory.cxx deleted file mode 100644 index 983f2c6314..0000000000 --- a/thirdparty/KWSys/adios2sys/testDirectory.cxx +++ /dev/null @@ -1,79 +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 -#include -#include - -#include - -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 testDirectory(int, char* []) -{ - return _doLongPathTest(); -} diff --git a/thirdparty/KWSys/adios2sys/testDynamicLoader.cxx b/thirdparty/KWSys/adios2sys/testDynamicLoader.cxx deleted file mode 100644 index b52ddda8bd..0000000000 --- a/thirdparty/KWSys/adios2sys/testDynamicLoader.cxx +++ /dev/null @@ -1,117 +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 /* 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 -#include - -// Include with <> instead of "" to avoid getting any in-source copy -// left on disk. -#include - -static std::string GetLibName(const char* lname) -{ - // Construct proper name of lib - std::string slname; - slname = EXECUTABLE_OUTPUT_PATH; -#ifdef CMAKE_INTDIR - slname += "/"; - slname += CMAKE_INTDIR; -#endif - slname += "/"; - slname += kwsys::DynamicLoader::LibPrefix(); - slname += lname; - slname += kwsys::DynamicLoader::LibExtension(); - - return slname; -} - -/* libname = Library name (proper prefix, proper extension) - * System = symbol to lookup in libname - * r1: should OpenLibrary succeed ? - * r2: should GetSymbolAddress succeed ? - * r3: should CloseLibrary succeed ? - */ -static int TestDynamicLoader(const char* libname, const char* symbol, int r1, - int r2, int r3) -{ - std::cerr << "Testing: " << libname << std::endl; - kwsys::DynamicLoader::LibraryHandle l = - kwsys::DynamicLoader::OpenLibrary(libname); - // If result is incompatible with expectation just fails (xor): - if ((r1 && !l) || (!r1 && l)) { - std::cerr << kwsys::DynamicLoader::LastError() << std::endl; - return 1; - } - kwsys::DynamicLoader::SymbolPointer f = - kwsys::DynamicLoader::GetSymbolAddress(l, symbol); - if ((r2 && !f) || (!r2 && f)) { - std::cerr << kwsys::DynamicLoader::LastError() << std::endl; - return 1; - } -#ifndef __APPLE__ - int s = kwsys::DynamicLoader::CloseLibrary(l); - if ((r3 && !s) || (!r3 && s)) { - std::cerr << kwsys::DynamicLoader::LastError() << std::endl; - return 1; - } -#else - (void)r3; -#endif - return 0; -} - -int testDynamicLoader(int argc, char* argv[]) -{ -#if defined(_WIN32) - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); -#elif defined(__BEOS__) || defined(__HAIKU__) - disable_debugger(1); -#endif - int res = 0; - if (argc == 3) { - // User specify a libname and symbol to check. - res = TestDynamicLoader(argv[1], argv[2], 1, 1, 1); - return res; - } - -// dlopen() on Syllable before 11/22/2007 doesn't return 0 on error -#ifndef __SYLLABLE__ - // Make sure that inexistent lib is giving correct result - res += TestDynamicLoader("azerty_", "foo_bar", 0, 0, 0); - // Make sure that random binary file cannot be assimilated as dylib - res += TestDynamicLoader(TEST_SYSTEMTOOLS_SOURCE_DIR "/testSystemTools.bin", - "wp", 0, 0, 0); -#endif - -#ifdef __linux__ - // This one is actually fun to test, since dlopen is by default - // loaded...wonder why :) - res += TestDynamicLoader("foobar.lib", "dlopen", 0, 1, 0); - res += TestDynamicLoader("libdl.so", "dlopen", 1, 1, 1); - res += TestDynamicLoader("libdl.so", "TestDynamicLoader", 1, 0, 1); -#endif - // Now try on the generated library - std::string libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynload"); - res += TestDynamicLoader(libname.c_str(), "dummy", 1, 0, 1); - res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderSymbolPointer", - 1, 1, 1); - res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderSymbolPointer", - 1, 0, 1); - res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1); - res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1); - - return res; -} diff --git a/thirdparty/KWSys/adios2sys/testDynload.c b/thirdparty/KWSys/adios2sys/testDynload.c deleted file mode 100644 index cdb9e5c358..0000000000 --- a/thirdparty/KWSys/adios2sys/testDynload.c +++ /dev/null @@ -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() -{ -} diff --git a/thirdparty/KWSys/adios2sys/testEncode.c b/thirdparty/KWSys/adios2sys/testEncode.c deleted file mode 100644 index a20d46fd3b..0000000000 --- a/thirdparty/KWSys/adios2sys/testEncode.c +++ /dev/null @@ -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 -#include - -static const unsigned char testMD5input1[] = - " A quick brown fox jumps over the lazy dog.\n" - " This is sample text for MD5 sum input.\n"; -static const char testMD5output1[] = "8f146af46ed4f267921bb937d4d3500c"; - -static const int testMD5input2len = 28; -static const unsigned char testMD5input2[] = "the cow jumped over the moon"; -static const char testMD5output2[] = "a2ad137b746138fae4e5adca9c85d3ae"; - -static int testMD5_1(kwsysMD5* md5) -{ - char md5out[33]; - kwsysMD5_Initialize(md5); - kwsysMD5_Append(md5, testMD5input1, -1); - kwsysMD5_FinalizeHex(md5, md5out); - md5out[32] = 0; - printf("md5sum 1: expected [%s]\n" - " got [%s]\n", - testMD5output1, md5out); - return (strcmp(md5out, testMD5output1) != 0) ? 1 : 0; -} - -static int testMD5_2(kwsysMD5* md5) -{ - unsigned char digest[16]; - char md5out[33]; - kwsysMD5_Initialize(md5); - kwsysMD5_Append(md5, testMD5input2, testMD5input2len); - kwsysMD5_Finalize(md5, digest); - kwsysMD5_DigestToHex(digest, md5out); - md5out[32] = 0; - printf("md5sum 2: expected [%s]\n" - " got [%s]\n", - testMD5output2, md5out); - return (strcmp(md5out, testMD5output2) != 0) ? 1 : 0; -} - -int testEncode(int argc, char* argv[]) -{ - int result = 0; - (void)argc; - (void)argv; - - /* Test MD5 digest. */ - { - kwsysMD5* md5 = kwsysMD5_New(); - result |= testMD5_1(md5); - result |= testMD5_2(md5); - kwsysMD5_Delete(md5); - } - - return result; -} diff --git a/thirdparty/KWSys/adios2sys/testEncoding.cxx b/thirdparty/KWSys/adios2sys/testEncoding.cxx deleted file mode 100644 index 6bf273f2c5..0000000000 --- a/thirdparty/KWSys/adios2sys/testEncoding.cxx +++ /dev/null @@ -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 -#include -#include -#include -#include - -// 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(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(KWSYS_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(KWSYS_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 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::iterator it = strings.begin(); - it != strings.end(); ++it) { - std::wstring wstr = kwsys::Encoding::ToWide(*it); - std::string str = kwsys::Encoding::ToNarrow(wstr); - std::string s(*it); - std::replace(s.begin(), s.end(), '\0', ' '); - std::cout << "'" << s << "' (" << it->size() << ")" << std::endl; - if (str != *it) { - std::replace(str.begin(), str.end(), '\0', ' '); - std::cout << "string with null was different: '" << str << "' (" - << str.size() << ")" << std::endl; - ret++; - } - } - return ret; -} - -static int testCommandLineArguments() -{ - int status = 0; - - char const* argv[2] = { "./app.exe", (char const*)helloWorldStrings[1] }; - - kwsys::Encoding::CommandLineArguments args(2, argv); - kwsys::Encoding::CommandLineArguments arg2 = - kwsys::Encoding::CommandLineArguments(args); - - char const* const* u8_argv = args.argv(); - for (int i = 0; i < args.argc(); i++) { - char const* u8_arg = u8_argv[i]; - if (strcmp(argv[i], u8_arg) != 0) { - std::cout << "argv[" << i << "] " << argv[i] << " != " << u8_arg - << std::endl; - status++; - } - } - - kwsys::Encoding::CommandLineArguments args3 = - kwsys::Encoding::CommandLineArguments::Main(2, argv); - - return status; -} - -static int testToWindowsExtendedPath() -{ -#ifdef _WIN32 - int ret = 0; - if (kwsys::Encoding::ToWindowsExtendedPath( - "L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") != - L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"" - << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath( - "L:/Local Mojo/Hex Power Pack/Iffy Voodoo") != - L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath( - "\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") != - L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"" - << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath( - "//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") != - L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\"" - << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("//") != L"//") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"//\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\") != L"\\\\.\\") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\.\\\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X") != L"\\\\.\\X") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\.\\X\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:") != L"\\\\?\\X:") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\.\\X:\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:\\") != - L"\\\\?\\X:\\") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\.\\X:\\\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("NUL") != L"\\\\.\\NUL") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"NUL\"" << std::endl; - ++ret; - } - - return ret; -#else - return 0; -#endif -} - -int testEncoding(int, char* []) -{ - const char* loc = setlocale(LC_ALL, ""); - if (loc) { - std::cout << "Locale: " << loc << std::endl; - } else { - std::cout << "Locale: None" << std::endl; - } - - int ret = 0; - - ret |= testHelloWorldEncoding(); - ret |= testRobustEncoding(); - ret |= testCommandLineArguments(); - ret |= testWithNulls(); - ret |= testToWindowsExtendedPath(); - - return ret; -} diff --git a/thirdparty/KWSys/adios2sys/testFStream.cxx b/thirdparty/KWSys/adios2sys/testFStream.cxx deleted file mode 100644 index a92a781c38..0000000000 --- a/thirdparty/KWSys/adios2sys/testFStream.cxx +++ /dev/null @@ -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 -#ifdef __BORLANDC__ -#include /* memcmp */ -#endif - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -#include "FStream.hxx.in" -#endif - -#include - -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(expected_bom_data[i] + 1), - *expected_bom_data[i]); - out.write(reinterpret_cast(file_data[i] + 1), - file_data[i][0]); - } - - kwsys::ifstream in("bom.txt", kwsys::ofstream::binary); - kwsys::FStream::BOM bom = kwsys::FStream::ReadBOM(in); - if (bom != expected_bom[i]) { - std::cout << "Unexpected BOM " << i << std::endl; - return 1; - } - char data[max_test_file_size]; - in.read(data, file_data[i][0]); - if (!in.good()) { - std::cout << "Unable to read data " << i << std::endl; - return 1; - } - - if (memcmp(data, file_data[i] + 1, file_data[i][0]) != 0) { - std::cout << "Incorrect read data " << i << std::endl; - return 1; - } - } - - return 0; -} - -int testFStream(int, char* []) -{ - int ret = 0; - - ret |= testNoFile(); - ret |= testBOM(); - - return ret; -} diff --git a/thirdparty/KWSys/adios2sys/testFail.c b/thirdparty/KWSys/adios2sys/testFail.c deleted file mode 100644 index 82caeac37f..0000000000 --- a/thirdparty/KWSys/adios2sys/testFail.c +++ /dev/null @@ -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 -#include -#include - -int testFail(int argc, char* argv[]) -{ - char* env = getenv("DASHBOARD_TEST_FROM_CTEST"); - int oldCtest = 0; - if (env) { - if (strcmp(env, "1") == 0) { - oldCtest = 1; - } - printf("DASHBOARD_TEST_FROM_CTEST = %s\n", env); - } - printf("%s: This test intentionally fails\n", argv[0]); - if (oldCtest) { - printf("The version of ctest is not able to handle intentionally failing " - "tests, so pass.\n"); - return 0; - } - return argc; -} diff --git a/thirdparty/KWSys/adios2sys/testHashSTL.cxx b/thirdparty/KWSys/adios2sys/testHashSTL.cxx deleted file mode 100644 index 0444874732..0000000000 --- a/thirdparty/KWSys/adios2sys/testHashSTL.cxx +++ /dev/null @@ -1,63 +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(hash_map.hxx) -#include KWSYS_HEADER(hash_set.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -#include "hash_map.hxx.in" -#include "hash_set.hxx.in" -#endif - -#include - -#if defined(_MSC_VER) -#pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) -#pragma set woff 1468 /* inline function cannot be explicitly instantiated */ -#endif - -template class kwsys::hash_map; -template class kwsys::hash_set; - -static bool test_hash_map() -{ - typedef kwsys::hash_map mtype; - mtype m; - const char* keys[] = { "hello", "world" }; - m[keys[0]] = 1; - m.insert(mtype::value_type(keys[1], 2)); - int sum = 0; - for (mtype::iterator mi = m.begin(); mi != m.end(); ++mi) { - std::cout << "Found entry [" << mi->first << "," << mi->second << "]" - << std::endl; - sum += mi->second; - } - return sum == 3; -} - -static bool test_hash_set() -{ - typedef kwsys::hash_set stype; - stype s; - s.insert(1); - s.insert(2); - int sum = 0; - for (stype::iterator si = s.begin(); si != s.end(); ++si) { - std::cout << "Found entry [" << *si << "]" << std::endl; - sum += *si; - } - return sum == 3; -} - -int testHashSTL(int, char* []) -{ - bool result = true; - result = test_hash_map() && result; - result = test_hash_set() && result; - return result ? 0 : 1; -} diff --git a/thirdparty/KWSys/adios2sys/testProcess.c b/thirdparty/KWSys/adios2sys/testProcess.c deleted file mode 100644 index 4b4978dfe5..0000000000 --- a/thirdparty/KWSys/adios2sys/testProcess.c +++ /dev/null @@ -1,725 +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 - -#include -#include -#include -#include -#include - -#if defined(_WIN32) -#include -#else -#include -#include -#endif - -#if defined(__BORLANDC__) -#pragma warn - 8060 /* possibly incorrect assignment */ -#endif - -/* Platform-specific sleep functions. */ - -#if defined(__BEOS__) && !defined(__ZETA__) -/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ -#include -static inline void testProcess_usleep(unsigned int usec) -{ - snooze(usec); -} -#elif defined(_WIN32) -/* Windows can only sleep in millisecond intervals. */ -static void testProcess_usleep(unsigned int usec) -{ - Sleep(usec / 1000); -} -#else -#define testProcess_usleep usleep -#endif - -#if defined(_WIN32) -static void testProcess_sleep(unsigned int sec) -{ - Sleep(sec * 1000); -} -#else -static void testProcess_sleep(unsigned int sec) -{ - sleep(sec); -} -#endif - -int runChild(const char* cmd[], int state, int exception, int value, int share, - int output, int delay, double timeout, int poll, int repeat, - int disown, int createNewGroup, unsigned int interruptDelay); - -static int test1(int argc, const char* argv[]) -{ - /* This is a very basic functional test of kwsysProcess. It is repeated - numerous times to verify that there are no resource leaks in kwsysProcess - that eventually lead to an error. Many versions of OS X will fail after - 256 leaked file handles, so 257 iterations seems to be a good test. On - the other hand, too many iterations will cause the test to time out - - especially if the test is instrumented with e.g. valgrind. - - If you have problems with this test timing out on your system, or want to - run more than 257 iterations, you can change the number of iterations by - setting the KWSYS_TEST_PROCESS_1_COUNT environment variable. */ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout from test returning 0.\n"); - fprintf(stderr, "Output on stderr from test returning 0.\n"); - return 0; -} - -static int test2(int argc, const char* argv[]) -{ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout from test returning 123.\n"); - fprintf(stderr, "Output on stderr from test returning 123.\n"); - return 123; -} - -static int test3(int argc, const char* argv[]) -{ - (void)argc; - (void)argv; - fprintf(stdout, "Output before sleep on stdout from timeout test.\n"); - fprintf(stderr, "Output before sleep on stderr from timeout test.\n"); - fflush(stdout); - fflush(stderr); - testProcess_sleep(15); - fprintf(stdout, "Output after sleep on stdout from timeout test.\n"); - fprintf(stderr, "Output after sleep on stderr from timeout test.\n"); - return 0; -} - -static int test4(int argc, const char* argv[]) -{ -#ifndef CRASH_USING_ABORT - /* Prepare a pointer to an invalid address. Don't use null, because - dereferencing null is undefined behaviour and compilers are free to - do whatever they want. ex: Clang will warn at compile time, or even - optimize away the write. We hope to 'outsmart' them by using - 'volatile' and a slightly larger address, based on a runtime value. */ - volatile int* invalidAddress = 0; - invalidAddress += argc ? 1 : 2; -#endif - -#if defined(_WIN32) - /* Avoid error diagnostic popups since we are crashing on purpose. */ - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); -#elif defined(__BEOS__) || defined(__HAIKU__) - /* Avoid error diagnostic popups since we are crashing on purpose. */ - disable_debugger(1); -#endif - (void)argc; - (void)argv; - fprintf(stdout, "Output before crash on stdout from crash test.\n"); - fprintf(stderr, "Output before crash on stderr from crash test.\n"); - fflush(stdout); - fflush(stderr); -#ifdef CRASH_USING_ABORT - abort(); -#else - assert(invalidAddress); /* Quiet Clang scan-build. */ - /* Provoke deliberate crash by writing to the invalid address. */ - *invalidAddress = 0; -#endif - fprintf(stdout, "Output after crash on stdout from crash test.\n"); - fprintf(stderr, "Output after crash on stderr from crash test.\n"); - return 0; -} - -static int test5(int argc, const char* argv[]) -{ - int r; - const char* cmd[4]; - (void)argc; - cmd[0] = argv[0]; - cmd[1] = "run"; - cmd[2] = "4"; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before recursive test.\n"); - fprintf(stderr, "Output on stderr before recursive test.\n"); - fflush(stdout); - fflush(stderr); - r = runChild(cmd, kwsysProcess_State_Exception, -#ifdef CRASH_USING_ABORT - kwsysProcess_Exception_Other, -#else - kwsysProcess_Exception_Fault, -#endif - 1, 1, 1, 0, 15, 0, 1, 0, 0, 0); - fprintf(stdout, "Output on stdout after recursive test.\n"); - fprintf(stderr, "Output on stderr after recursive test.\n"); - fflush(stdout); - fflush(stderr); - return r; -} - -#define TEST6_SIZE (4096 * 2) -static void test6(int argc, const char* argv[]) -{ - int i; - char runaway[TEST6_SIZE + 1]; - (void)argc; - (void)argv; - for (i = 0; i < TEST6_SIZE; ++i) { - runaway[i] = '.'; - } - runaway[TEST6_SIZE] = '\n'; - - /* Generate huge amounts of output to test killing. */ - for (;;) { - fwrite(runaway, 1, TEST6_SIZE + 1, stdout); - fflush(stdout); - } -} - -/* Define MINPOLL to be one more than the number of times output is - written. Define MAXPOLL to be the largest number of times a loop - delaying 1/10th of a second should ever have to poll. */ -#define MINPOLL 5 -#define MAXPOLL 20 -static int test7(int argc, const char* argv[]) -{ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout before sleep.\n"); - fprintf(stderr, "Output on stderr before sleep.\n"); - fflush(stdout); - fflush(stderr); - /* Sleep for 1 second. */ - testProcess_sleep(1); - fprintf(stdout, "Output on stdout after sleep.\n"); - fprintf(stderr, "Output on stderr after sleep.\n"); - fflush(stdout); - fflush(stderr); - return 0; -} - -static int test8(int argc, const char* argv[]) -{ - /* Create a disowned grandchild to test handling of processes - that exit before their children. */ - int r; - const char* cmd[4]; - (void)argc; - cmd[0] = argv[0]; - cmd[1] = "run"; - cmd[2] = "108"; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before grandchild test.\n"); - fprintf(stderr, "Output on stderr before grandchild test.\n"); - fflush(stdout); - fflush(stderr); - r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None, - 1, 1, 1, 0, 10, 0, 1, 1, 0, 0); - fprintf(stdout, "Output on stdout after grandchild test.\n"); - fprintf(stderr, "Output on stderr after grandchild test.\n"); - fflush(stdout); - fflush(stderr); - return r; -} - -static int test8_grandchild(int argc, const char* argv[]) -{ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); - fflush(stdout); - fflush(stderr); - /* TODO: Instead of closing pipes here leave them open to make sure - the grandparent can stop listening when the parent exits. This - part of the test cannot be enabled until the feature is - implemented. */ - fclose(stdout); - fclose(stderr); - testProcess_sleep(15); - return 0; -} - -static int test9(int argc, const char* argv[]) -{ - /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this - process. Here, we start a child process that sleeps for a long time - while ignoring signals. The test is successful if this process waits - for the child to return before exiting from the Ctrl+C handler. - - WARNING: This test will falsely pass if the share parameter of runChild - was set to 0 when invoking the test9 process. */ - int r; - const char* cmd[4]; - (void)argc; - cmd[0] = argv[0]; - cmd[1] = "run"; - cmd[2] = "109"; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before grandchild test.\n"); - fprintf(stderr, "Output on stderr before grandchild test.\n"); - fflush(stdout); - fflush(stderr); - r = runChild(cmd, kwsysProcess_State_Exited, kwsysProcess_Exception_None, 0, - 1, 1, 0, 30, 0, 1, 0, 0, 0); - /* This sleep will avoid a race condition between this function exiting - normally and our Ctrl+C handler exiting abnormally after the process - exits. */ - testProcess_sleep(1); - fprintf(stdout, "Output on stdout after grandchild test.\n"); - fprintf(stderr, "Output on stderr after grandchild test.\n"); - fflush(stdout); - fflush(stderr); - return r; -} - -#if defined(_WIN32) -static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType) -{ - /* Ignore all Ctrl+C/Break signals. We must use an actual handler function - instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also - ignore Ctrl+Break in addition to Ctrl+C. */ - (void)dwCtrlType; - return TRUE; -} -#endif - -static int test9_grandchild(int argc, const char* argv[]) -{ - /* The grandchild just sleeps for a few seconds while ignoring signals. */ - (void)argc; - (void)argv; -#if defined(_WIN32) - if (!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE)) { - return 1; - } -#else - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - if (sigaction(SIGINT, &sa, 0) < 0) { - return 1; - } -#endif - fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); - fflush(stdout); - fflush(stderr); - /* Sleep for 9 seconds. */ - testProcess_sleep(9); - fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); - fflush(stdout); - fflush(stderr); - return 0; -} - -static int test10(int argc, const char* argv[]) -{ - /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this - process. Here, we start a child process that sleeps for a long time and - processes signals normally. However, this grandchild is created in a new - process group - ensuring that Ctrl+C we receive is sent to our process - groups. We make sure it exits anyway. */ - int r; - const char* cmd[4]; - (void)argc; - cmd[0] = argv[0]; - cmd[1] = "run"; - cmd[2] = "110"; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before grandchild test.\n"); - fprintf(stderr, "Output on stderr before grandchild test.\n"); - fflush(stdout); - fflush(stderr); - r = - runChild(cmd, kwsysProcess_State_Exception, - kwsysProcess_Exception_Interrupt, 0, 1, 1, 0, 30, 0, 1, 0, 1, 0); - fprintf(stdout, "Output on stdout after grandchild test.\n"); - fprintf(stderr, "Output on stderr after grandchild test.\n"); - fflush(stdout); - fflush(stderr); - return r; -} - -static int test10_grandchild(int argc, const char* argv[]) -{ - /* The grandchild just sleeps for a few seconds and handles signals. */ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); - fflush(stdout); - fflush(stderr); - /* Sleep for 6 seconds. */ - testProcess_sleep(6); - fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); - fflush(stdout); - fflush(stderr); - return 0; -} - -static int runChild2(kwsysProcess* kp, const char* cmd[], int state, - int exception, int value, int share, int output, - int delay, double timeout, int poll, int disown, - int createNewGroup, unsigned int interruptDelay) -{ - int result = 0; - char* data = 0; - int length = 0; - double userTimeout = 0; - double* pUserTimeout = 0; - kwsysProcess_SetCommand(kp, cmd); - if (timeout >= 0) { - kwsysProcess_SetTimeout(kp, timeout); - } - if (share) { - kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1); - kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1); - } - if (disown) { - kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1); - } - if (createNewGroup) { - kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1); - } - kwsysProcess_Execute(kp); - - if (poll) { - pUserTimeout = &userTimeout; - } - - if (interruptDelay) { - testProcess_sleep(interruptDelay); - kwsysProcess_Interrupt(kp); - } - - if (!share && !disown) { - int p; - while ((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout))) { - if (output) { - if (poll && p == kwsysProcess_Pipe_Timeout) { - fprintf(stdout, "WaitForData timeout reached.\n"); - fflush(stdout); - - /* Count the number of times we polled without getting data. - If it is excessive then kill the child and fail. */ - if (++poll >= MAXPOLL) { - fprintf(stdout, "Poll count reached limit %d.\n", MAXPOLL); - kwsysProcess_Kill(kp); - } - } else { - fwrite(data, 1, (size_t)length, stdout); - fflush(stdout); - } - } - if (poll) { - /* Delay to avoid busy loop during polling. */ - testProcess_usleep(100000); - } - if (delay) { -/* Purposely sleeping only on Win32 to let pipe fill up. */ -#if defined(_WIN32) - testProcess_usleep(100000); -#endif - } - } - } - - if (disown) { - kwsysProcess_Disown(kp); - } else { - kwsysProcess_WaitForExit(kp, 0); - } - - switch (kwsysProcess_GetState(kp)) { - case kwsysProcess_State_Starting: - printf("No process has been executed.\n"); - break; - case kwsysProcess_State_Executing: - printf("The process is still executing.\n"); - break; - case kwsysProcess_State_Expired: - printf("Child was killed when timeout expired.\n"); - break; - case kwsysProcess_State_Exited: - printf("Child exited with value = %d\n", kwsysProcess_GetExitValue(kp)); - result = ((exception != kwsysProcess_GetExitException(kp)) || - (value != kwsysProcess_GetExitValue(kp))); - break; - case kwsysProcess_State_Killed: - printf("Child was killed by parent.\n"); - break; - case kwsysProcess_State_Exception: - printf("Child terminated abnormally: %s\n", - kwsysProcess_GetExceptionString(kp)); - result = ((exception != kwsysProcess_GetExitException(kp)) || - (value != kwsysProcess_GetExitValue(kp))); - break; - case kwsysProcess_State_Disowned: - printf("Child was disowned.\n"); - break; - case kwsysProcess_State_Error: - printf("Error in administrating child process: [%s]\n", - kwsysProcess_GetErrorString(kp)); - break; - }; - - if (result) { - if (exception != kwsysProcess_GetExitException(kp)) { - fprintf(stderr, "Mismatch in exit exception. " - "Should have been %d, was %d.\n", - exception, kwsysProcess_GetExitException(kp)); - } - if (value != kwsysProcess_GetExitValue(kp)) { - fprintf(stderr, "Mismatch in exit value. " - "Should have been %d, was %d.\n", - value, kwsysProcess_GetExitValue(kp)); - } - } - - if (kwsysProcess_GetState(kp) != state) { - fprintf(stderr, "Mismatch in state. " - "Should have been %d, was %d.\n", - state, kwsysProcess_GetState(kp)); - result = 1; - } - - /* We should have polled more times than there were data if polling - was enabled. */ - if (poll && poll < MINPOLL) { - fprintf(stderr, "Poll count is %d, which is less than %d.\n", poll, - MINPOLL); - result = 1; - } - - return result; -} - -/** - * Runs a child process and blocks until it returns. Arguments as follows: - * - * cmd = Command line to run. - * state = Expected return value of kwsysProcess_GetState after exit. - * exception = Expected return value of kwsysProcess_GetExitException. - * value = Expected return value of kwsysProcess_GetExitValue. - * share = Whether to share stdout/stderr child pipes with our pipes - * by way of kwsysProcess_SetPipeShared. If false, new pipes - * are created. - * output = If !share && !disown, whether to write the child's stdout - * and stderr output to our stdout. - * delay = If !share && !disown, adds an additional short delay to - * the pipe loop to allow the pipes to fill up; Windows only. - * timeout = Non-zero to sets a timeout in seconds via - * kwsysProcess_SetTimeout. - * poll = If !share && !disown, we count the number of 0.1 second - * intervals where the child pipes had no new data. We fail - * if not in the bounds of MINPOLL/MAXPOLL. - * repeat = Number of times to run the process. - * disown = If set, the process is disowned. - * createNewGroup = If set, the process is created in a new process group. - * interruptDelay = If non-zero, number of seconds to delay before - * interrupting the process. Note that this delay will occur - * BEFORE any reading/polling of pipes occurs and before any - * detachment occurs. - */ -int runChild(const char* cmd[], int state, int exception, int value, int share, - int output, int delay, double timeout, int poll, int repeat, - int disown, int createNewGroup, unsigned int interruptDelay) -{ - int result = 1; - kwsysProcess* kp = kwsysProcess_New(); - if (!kp) { - fprintf(stderr, "kwsysProcess_New returned NULL!\n"); - return 1; - } - while (repeat-- > 0) { - result = runChild2(kp, cmd, state, exception, value, share, output, delay, - timeout, poll, disown, createNewGroup, interruptDelay); - if (result) { - break; - } - } - kwsysProcess_Delete(kp); - return result; -} - -int main(int argc, const char* argv[]) -{ - int n = 0; - -#ifdef _WIN32 - int i; - char new_args[10][_MAX_PATH]; - LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &argc); - for (i = 0; i < argc; i++) { - kwsysEncoding_wcstombs(new_args[i], w_av[i], _MAX_PATH); - argv[i] = new_args[i]; - } - LocalFree(w_av); -#endif - -#if 0 - { - HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); - DuplicateHandle(GetCurrentProcess(), out, - GetCurrentProcess(), &out, 0, FALSE, - DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - SetStdHandle(STD_OUTPUT_HANDLE, out); - } - { - HANDLE out = GetStdHandle(STD_ERROR_HANDLE); - DuplicateHandle(GetCurrentProcess(), out, - GetCurrentProcess(), &out, 0, FALSE, - DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - SetStdHandle(STD_ERROR_HANDLE, out); - } -#endif - if (argc == 2) { - n = atoi(argv[1]); - } else if (argc == 3 && strcmp(argv[1], "run") == 0) { - n = atoi(argv[2]); - } - /* Check arguments. */ - if (((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3) { - /* This is the child process for a requested test number. */ - switch (n) { - case 1: - return test1(argc, argv); - case 2: - return test2(argc, argv); - case 3: - return test3(argc, argv); - case 4: - return test4(argc, argv); - case 5: - return test5(argc, argv); - case 6: - test6(argc, argv); - return 0; - case 7: - return test7(argc, argv); - case 8: - return test8(argc, argv); - case 9: - return test9(argc, argv); - case 10: - return test10(argc, argv); - case 108: - return test8_grandchild(argc, argv); - case 109: - return test9_grandchild(argc, argv); - case 110: - return test10_grandchild(argc, argv); - } - fprintf(stderr, "Invalid test number %d.\n", n); - return 1; - } else if (n >= 1 && n <= 10) { - /* This is the parent process for a requested test number. */ - int states[10] = { - kwsysProcess_State_Exited, kwsysProcess_State_Exited, - kwsysProcess_State_Expired, kwsysProcess_State_Exception, - kwsysProcess_State_Exited, kwsysProcess_State_Expired, - kwsysProcess_State_Exited, kwsysProcess_State_Exited, - kwsysProcess_State_Expired, /* Ctrl+C handler test */ - kwsysProcess_State_Exception /* Process group test */ - }; - int exceptions[10] = { - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, -#ifdef CRASH_USING_ABORT - kwsysProcess_Exception_Other, -#else - kwsysProcess_Exception_Fault, -#endif - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, kwsysProcess_Exception_Interrupt - }; - int values[10] = { 0, 123, 1, 1, 0, 0, 0, 0, 1, 1 }; - int shares[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; - int outputs[10] = { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }; - int delays[10] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; - double timeouts[10] = { 10, 10, 10, 30, 30, 10, -1, 10, 6, 4 }; - int polls[10] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; - int repeat[10] = { 257, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - int createNewGroups[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; - unsigned int interruptDelays[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 2 }; - int r; - const char* cmd[4]; -#ifdef _WIN32 - char* argv0 = 0; -#endif - char* test1IterationsStr = getenv("KWSYS_TEST_PROCESS_1_COUNT"); - if (test1IterationsStr) { - long int test1Iterations = strtol(test1IterationsStr, 0, 10); - if (test1Iterations > 10 && test1Iterations != LONG_MAX) { - repeat[0] = (int)test1Iterations; - } - } -#ifdef _WIN32 - if (n == 0 && (argv0 = strdup(argv[0]))) { - /* Try converting to forward slashes to see if it works. */ - char* c; - for (c = argv0; *c; ++c) { - if (*c == '\\') { - *c = '/'; - } - } - cmd[0] = argv0; - } else { - cmd[0] = argv[0]; - } -#else - cmd[0] = argv[0]; -#endif - cmd[1] = "run"; - cmd[2] = argv[1]; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before test %d.\n", n); - fprintf(stderr, "Output on stderr before test %d.\n", n); - fflush(stdout); - fflush(stderr); - r = runChild(cmd, states[n - 1], exceptions[n - 1], values[n - 1], - shares[n - 1], outputs[n - 1], delays[n - 1], timeouts[n - 1], - polls[n - 1], repeat[n - 1], 0, createNewGroups[n - 1], - interruptDelays[n - 1]); - fprintf(stdout, "Output on stdout after test %d.\n", n); - fprintf(stderr, "Output on stderr after test %d.\n", n); - fflush(stdout); - fflush(stderr); -#if defined(_WIN32) - free(argv0); -#endif - return r; - } else if (argc > 2 && strcmp(argv[1], "0") == 0) { - /* This is the special debugging test to run a given command - line. */ - const char** cmd = argv + 2; - int state = kwsysProcess_State_Exited; - int exception = kwsysProcess_Exception_None; - int value = 0; - double timeout = 0; - int r = - runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0, 0, 0); - return r; - } else { - /* Improper usage. */ - fprintf(stdout, "Usage: %s \n", argv[0]); - return 1; - } -} diff --git a/thirdparty/KWSys/adios2sys/testSharedForward.c.in b/thirdparty/KWSys/adios2sys/testSharedForward.c.in deleted file mode 100644 index 9a0c0c0614..0000000000 --- a/thirdparty/KWSys/adios2sys/testSharedForward.c.in +++ /dev/null @@ -1,27 +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(CMAKE_INTDIR) -#define CONFIG_DIR_PRE CMAKE_INTDIR "/" -#define CONFIG_DIR_POST "/" CMAKE_INTDIR -#else -#define CONFIG_DIR_PRE "" -#define CONFIG_DIR_POST "" -#endif -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "@EXEC_DIR@" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL 0 -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD \ - CONFIG_DIR_PRE "@KWSYS_NAMESPACE@TestProcess" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL \ - "@KWSYS_NAMESPACE@TestProcess" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd" -#if defined(CMAKE_INTDIR) -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR -#endif -#include <@KWSYS_NAMESPACE@/SharedForward.h> -int main(int argc, char** argv) -{ - return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv); -} diff --git a/thirdparty/KWSys/adios2sys/testSystemInformation.cxx b/thirdparty/KWSys/adios2sys/testSystemInformation.cxx deleted file mode 100644 index 3a9217f2c7..0000000000 --- a/thirdparty/KWSys/adios2sys/testSystemInformation.cxx +++ /dev/null @@ -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. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(SystemInformation.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -#include "SystemInformation.hxx.in" -#endif - -#include - -#if defined(KWSYS_USE_LONG_LONG) -#if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) -#define iostreamLongLong(x) (x) -#else -#define iostreamLongLong(x) ((long)x) -#endif -#elif defined(KWSYS_USE___INT64) -#if defined(KWSYS_IOS_HAS_OSTREAM___INT64) -#define iostreamLongLong(x) (x) -#else -#define iostreamLongLong(x) ((long)x) -#endif -#else -#error "No Long Long" -#endif - -#define printMethod(info, m) std::cout << #m << ": " << info.m() << "\n" - -#define printMethod2(info, m, unit) \ - std::cout << #m << ": " << info.m() << " " << unit << "\n" - -#define printMethod3(info, m, unit) \ - std::cout << #m << ": " << iostreamLongLong(info.m) << " " << unit << "\n" - -int testSystemInformation(int, char* []) -{ - std::cout << "CTEST_FULL_OUTPUT\n"; // avoid truncation - - kwsys::SystemInformation info; - info.RunCPUCheck(); - info.RunOSCheck(); - info.RunMemoryCheck(); - printMethod(info, GetOSName); - printMethod(info, GetOSIsLinux); - printMethod(info, GetOSIsApple); - printMethod(info, GetOSIsWindows); - printMethod(info, GetHostname); - printMethod(info, GetFullyQualifiedDomainName); - printMethod(info, GetOSRelease); - printMethod(info, GetOSVersion); - printMethod(info, GetOSPlatform); - printMethod(info, Is64Bits); - printMethod(info, GetVendorString); - printMethod(info, GetVendorID); - printMethod(info, GetTypeID); - printMethod(info, GetFamilyID); - printMethod(info, GetModelID); - printMethod(info, GetExtendedProcessorName); - printMethod(info, GetSteppingCode); - printMethod(info, GetProcessorSerialNumber); - printMethod2(info, GetProcessorCacheSize, "KB"); - printMethod(info, GetLogicalProcessorsPerPhysical); - printMethod2(info, GetProcessorClockFrequency, "MHz"); - printMethod(info, GetNumberOfLogicalCPU); - printMethod(info, GetNumberOfPhysicalCPU); - printMethod(info, DoesCPUSupportCPUID); - printMethod(info, GetProcessorAPICID); - printMethod2(info, GetTotalVirtualMemory, "MB"); - printMethod2(info, GetAvailableVirtualMemory, "MB"); - printMethod2(info, GetTotalPhysicalMemory, "MB"); - printMethod2(info, GetAvailablePhysicalMemory, "MB"); - printMethod3(info, GetHostMemoryTotal(), "KiB"); - printMethod3(info, GetHostMemoryAvailable("KWSHL"), "KiB"); - printMethod3(info, GetProcMemoryAvailable("KWSHL", "KWSPL"), "KiB"); - printMethod3(info, GetHostMemoryUsed(), "KiB"); - printMethod3(info, GetProcMemoryUsed(), "KiB"); - printMethod(info, GetLoadAverage); - - for (long int i = 0; i <= 31; i++) { - if (info.DoesCPUSupportFeature(static_cast(1) << i)) { - std::cout << "CPU feature " << i << "\n"; - } - } - - /* test stack trace - */ - std::cout << "Program Stack:" << std::endl - << kwsys::SystemInformation::GetProgramStack(0, 0) << std::endl - << std::endl; - - /* test segv handler - info.SetStackTraceOnError(1); - double *d = (double*)100; - *d=0; - */ - - /* test abort handler - info.SetStackTraceOnError(1); - abort(); - */ - - return 0; -} diff --git a/thirdparty/KWSys/adios2sys/testSystemTools.bin b/thirdparty/KWSys/adios2sys/testSystemTools.bin deleted file mode 100644 index 961a4043b9b2785351ab26a33cfcb1f366c1391b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 766 zcmbV~J8r`;5JX3D078KQr%G#;xrK8icPgzTq*cc{r`QAV5H3@?bYXZsLq;FVX_BRe z%g5!cJ`hlGG|ej%-%r3B^E=g0A5?{B&Opc7@6oZyO4pUdnM;@%vkIOsxNAjmXiL+d z<7 zAIM?AiVDY~%?XgU=c3&OkPg?P^8282@1&KxNx}UnZQM`N*8ME)+%M9>{YuT^22-rR A-v9sr diff --git a/thirdparty/KWSys/adios2sys/testSystemTools.cxx b/thirdparty/KWSys/adios2sys/testSystemTools.cxx deleted file mode 100644 index a6d934b14f..0000000000 --- a/thirdparty/KWSys/adios2sys/testSystemTools.cxx +++ /dev/null @@ -1,957 +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 KWSYS_HEADER(SystemTools.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -#include "FStream.hxx.in" -#include "SystemTools.hxx.in" -#endif - -// Include with <> instead of "" to avoid getting any in-source copy -// left on disk. -#include - -#include -#include -#include /* free */ -#include /* strcmp */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#include /* _umask (MSVC) / umask (Borland) */ -#ifdef _MSC_VER -#define umask _umask // Note this is still umask on Borland -#endif -#endif -#include /* umask (POSIX), _S_I* constants (Windows) */ -// Visual C++ does not define mode_t (note that Borland does, however). -#if defined(_MSC_VER) -typedef unsigned short mode_t; -#endif - -static const char* toUnixPaths[][2] = { - { "/usr/local/bin/passwd", "/usr/local/bin/passwd" }, - { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" }, - { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, - { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" }, - { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" }, - { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, - { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" }, - { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" }, - { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, - { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" }, - { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" }, - { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, - { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" }, - { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" }, - { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo/ cal/bin/pa/ sswd" }, - { KWSYS_NULLPTR, KWSYS_NULLPTR } -}; - -static bool CheckConvertToUnixSlashes(std::string const& input, - std::string const& output) -{ - std::string result = input; - kwsys::SystemTools::ConvertToUnixSlashes(result); - if (result != output) { - std::cerr << "Problem with ConvertToUnixSlashes - input: " << input - << " output: " << result << " expected: " << output << std::endl; - return false; - } - return true; -} - -static const char* checkEscapeChars[][4] = { - { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2" }, - { " {} ", "{}", "#", " #{#} " }, - { KWSYS_NULLPTR, KWSYS_NULLPTR, KWSYS_NULLPTR, KWSYS_NULLPTR } -}; - -static bool CheckEscapeChars(std::string const& input, - const char* chars_to_escape, char escape_char, - std::string const& output) -{ - std::string result = kwsys::SystemTools::EscapeChars( - input.c_str(), chars_to_escape, escape_char); - if (result != output) { - std::cerr << "Problem with CheckEscapeChars - input: " << input - << " output: " << result << " expected: " << output << std::endl; - return false; - } - return true; -} - -static bool CheckFileOperations() -{ - bool res = true; - const std::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR - "/testSystemToolsNonExistingFile"); - const std::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR "/."); - const std::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR - "/testSystemTools.bin"); - const std::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR - "/testSystemTools.cxx"); - const std::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR - "/testSystemToolsNewDir"); - const std::string testNewFile(testNewDir + "/testNewFile.txt"); - - if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) != - kwsys::SystemTools::FileTypeUnknown) { - std::cerr << "Problem with DetectFileType - failed to detect type of: " - << testNonExistingFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) != - kwsys::SystemTools::FileTypeUnknown) { - std::cerr << "Problem with DetectFileType - failed to detect type of: " - << testDotFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) != - kwsys::SystemTools::FileTypeBinary) { - std::cerr << "Problem with DetectFileType - failed to detect type of: " - << testBinFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) != - kwsys::SystemTools::FileTypeText) { - std::cerr << "Problem with DetectFileType - failed to detect type of: " - << testTxtFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::FileLength(testBinFile) != 766) { - std::cerr << "Problem with FileLength - incorrect length for: " - << testBinFile << std::endl; - res = false; - } - - kwsys::SystemTools::Stat_t buf; - if (kwsys::SystemTools::Stat(testTxtFile.c_str(), &buf) != 0) { - std::cerr << "Problem with Stat - unable to stat text file: " - << testTxtFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::Stat(testBinFile, &buf) != 0) { - std::cerr << "Problem with Stat - unable to stat bin file: " << testBinFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::MakeDirectory(testNewDir)) { - std::cerr << "Problem with MakeDirectory for: " << testNewDir << std::endl; - res = false; - } - // calling it again should just return true - if (!kwsys::SystemTools::MakeDirectory(testNewDir)) { - std::cerr << "Problem with second call to MakeDirectory for: " - << testNewDir << std::endl; - res = false; - } - // calling with 0 pointer should return false - if (kwsys::SystemTools::MakeDirectory(KWSYS_NULLPTR)) { - std::cerr << "Problem with MakeDirectory(0)" << std::endl; - res = false; - } - // calling with an empty string should return false - if (kwsys::SystemTools::MakeDirectory(std::string())) { - std::cerr << "Problem with MakeDirectory(std::string())" << std::endl; - res = false; - } - // check existence - if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { - std::cerr << "Problem with FileExists as C string and not file for: " - << testNewDir << std::endl; - res = false; - } - // check existence - if (!kwsys::SystemTools::PathExists(testNewDir)) { - std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; - res = false; - } - // remove it - if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { - std::cerr << "Problem with RemoveADirectory for: " << testNewDir - << std::endl; - res = false; - } - // check existence - if (kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { - std::cerr << "After RemoveADirectory: " - << "Problem with FileExists as C string and not file for: " - << testNewDir << std::endl; - res = false; - } - // check existence - if (kwsys::SystemTools::PathExists(testNewDir)) { - std::cerr << "After RemoveADirectory: " - << "Problem with PathExists for: " << testNewDir << std::endl; - res = false; - } - // create it using the char* version - if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str())) { - std::cerr << "Problem with second call to MakeDirectory as C string for: " - << testNewDir << std::endl; - res = false; - } - - if (!kwsys::SystemTools::Touch(testNewFile.c_str(), true)) { - std::cerr << "Problem with Touch for: " << testNewFile << std::endl; - res = false; - } - // calling MakeDirectory with something that is no file should fail - if (kwsys::SystemTools::MakeDirectory(testNewFile)) { - std::cerr << "Problem with to MakeDirectory for: " << testNewFile - << std::endl; - res = false; - } - - // calling with 0 pointer should return false - if (kwsys::SystemTools::FileExists(KWSYS_NULLPTR)) { - std::cerr << "Problem with FileExists(0)" << std::endl; - res = false; - } - if (kwsys::SystemTools::FileExists(KWSYS_NULLPTR, true)) { - std::cerr << "Problem with FileExists(0) as file" << std::endl; - res = false; - } - // calling with an empty string should return false - if (kwsys::SystemTools::FileExists(std::string())) { - std::cerr << "Problem with FileExists(std::string())" << std::endl; - res = false; - } - // FileExists(x, true) should return false on a directory - if (kwsys::SystemTools::FileExists(testNewDir, true)) { - std::cerr << "Problem with FileExists as file for: " << testNewDir - << std::endl; - res = false; - } - if (kwsys::SystemTools::FileExists(testNewDir.c_str(), true)) { - std::cerr << "Problem with FileExists as C string and file for: " - << testNewDir << std::endl; - res = false; - } - // FileExists(x, false) should return true even on a directory - if (!kwsys::SystemTools::FileExists(testNewDir, false)) { - std::cerr << "Problem with FileExists as not file for: " << testNewDir - << std::endl; - res = false; - } - if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { - std::cerr << "Problem with FileExists as C string and not file for: " - << testNewDir << std::endl; - res = false; - } - // should work, was created as new file before - if (!kwsys::SystemTools::FileExists(testNewFile)) { - std::cerr << "Problem with FileExists for: " << testNewFile << std::endl; - res = false; - } - if (!kwsys::SystemTools::FileExists(testNewFile.c_str())) { - std::cerr << "Problem with FileExists as C string for: " << testNewFile - << std::endl; - res = false; - } - if (!kwsys::SystemTools::FileExists(testNewFile, true)) { - std::cerr << "Problem with FileExists as file for: " << testNewFile - << std::endl; - res = false; - } - if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true)) { - std::cerr << "Problem with FileExists as C string and file for: " - << testNewFile << std::endl; - res = false; - } - - // calling with an empty string should return false - if (kwsys::SystemTools::PathExists(std::string())) { - std::cerr << "Problem with PathExists(std::string())" << std::endl; - res = false; - } - // PathExists(x) should return true on a directory - if (!kwsys::SystemTools::PathExists(testNewDir)) { - std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; - res = false; - } - // should work, was created as new file before - if (!kwsys::SystemTools::PathExists(testNewFile)) { - std::cerr << "Problem with PathExists for: " << testNewFile << std::endl; - res = false; - } - -// Reset umask -#if defined(_WIN32) && !defined(__CYGWIN__) - // NOTE: Windows doesn't support toggling _S_IREAD. - mode_t fullMask = _S_IWRITE; -#else - // On a normal POSIX platform, we can toggle all permissions. - mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO; -#endif - mode_t orig_umask = umask(fullMask); - - // Test file permissions without umask - mode_t origPerm, thisPerm; - if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) { - std::cerr << "Problem with GetPermissions (1) for: " << testNewFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) { - std::cerr << "Problem with SetPermissions (1) for: " << testNewFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { - std::cerr << "Problem with GetPermissions (2) for: " << testNewFile - << std::endl; - res = false; - } - - if ((thisPerm & fullMask) != 0) { - std::cerr << "SetPermissions failed to set permissions (1) for: " - << testNewFile << ": actual = " << thisPerm - << "; expected = " << 0 << std::endl; - res = false; - } - - // While we're at it, check proper TestFileAccess functionality. - if (kwsys::SystemTools::TestFileAccess(testNewFile, - kwsys::TEST_FILE_WRITE)) { - std::cerr - << "TestFileAccess incorrectly indicated that this is a writable file:" - << testNewFile << std::endl; - res = false; - } - - if (!kwsys::SystemTools::TestFileAccess(testNewFile, kwsys::TEST_FILE_OK)) { - std::cerr - << "TestFileAccess incorrectly indicated that this file does not exist:" - << testNewFile << std::endl; - res = false; - } - - // Test restoring/setting full permissions. - if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask)) { - std::cerr << "Problem with SetPermissions (2) for: " << testNewFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { - std::cerr << "Problem with GetPermissions (3) for: " << testNewFile - << std::endl; - res = false; - } - - if ((thisPerm & fullMask) != fullMask) { - std::cerr << "SetPermissions failed to set permissions (2) for: " - << testNewFile << ": actual = " << thisPerm - << "; expected = " << fullMask << std::endl; - res = false; - } - - // Test setting file permissions while honoring umask - if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) { - std::cerr << "Problem with SetPermissions (3) for: " << testNewFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { - std::cerr << "Problem with GetPermissions (4) for: " << testNewFile - << std::endl; - res = false; - } - - if ((thisPerm & fullMask) != 0) { - std::cerr << "SetPermissions failed to honor umask for: " << testNewFile - << ": actual = " << thisPerm << "; expected = " << 0 - << std::endl; - res = false; - } - - // Restore umask - umask(orig_umask); - - // Restore file permissions - if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm)) { - std::cerr << "Problem with SetPermissions (4) for: " << testNewFile - << std::endl; - res = false; - } - - // Remove the test file - if (!kwsys::SystemTools::RemoveFile(testNewFile)) { - std::cerr << "Problem with RemoveFile: " << testNewFile << std::endl; - res = false; - } - - std::string const testFileMissing(testNewDir + "/testMissingFile.txt"); - if (!kwsys::SystemTools::RemoveFile(testFileMissing)) { - std::string const& msg = kwsys::SystemTools::GetLastSystemError(); - std::cerr << "RemoveFile(\"" << testFileMissing << "\") failed: " << msg - << "\n"; - res = false; - } - - std::string const testFileMissingDir(testNewDir + "/missing/file.txt"); - if (!kwsys::SystemTools::RemoveFile(testFileMissingDir)) { - std::string const& msg = kwsys::SystemTools::GetLastSystemError(); - std::cerr << "RemoveFile(\"" << testFileMissingDir << "\") failed: " << msg - << "\n"; - res = false; - } - - kwsys::SystemTools::Touch(testNewFile.c_str(), true); - if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { - std::cerr << "Problem with RemoveADirectory for: " << testNewDir - << std::endl; - res = false; - } - -#ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS - // Perform the same file and directory creation and deletion tests but - // with paths > 256 characters in length. - - const std::string testNewLongDir( - TEST_SYSTEMTOOLS_BINARY_DIR - "/" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "01234567890123"); - const std::string testNewLongFile( - testNewLongDir + - "/" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "0123456789.txt"); - - if (!kwsys::SystemTools::MakeDirectory(testNewLongDir)) { - std::cerr << "Problem with MakeDirectory for: " << testNewLongDir - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true)) { - std::cerr << "Problem with Touch for: " << testNewLongFile << std::endl; - res = false; - } - - if (!kwsys::SystemTools::RemoveFile(testNewLongFile)) { - std::cerr << "Problem with RemoveFile: " << testNewLongFile << std::endl; - res = false; - } - - kwsys::SystemTools::Touch(testNewLongFile.c_str(), true); - if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir)) { - std::cerr << "Problem with RemoveADirectory for: " << testNewLongDir - << std::endl; - res = false; - } -#endif - - return res; -} - -static bool CheckStringOperations() -{ - bool res = true; - - std::string test = "mary had a little lamb."; - if (kwsys::SystemTools::CapitalizedWords(test) != - "Mary Had A Little Lamb.") { - std::cerr << "Problem with CapitalizedWords " << '"' << test << '"' - << std::endl; - res = false; - } - - test = "Mary Had A Little Lamb."; - if (kwsys::SystemTools::UnCapitalizedWords(test) != - "mary had a little lamb.") { - std::cerr << "Problem with UnCapitalizedWords " << '"' << test << '"' - << std::endl; - res = false; - } - - test = "MaryHadTheLittleLamb."; - if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) != - "Mary Had The Little Lamb.") { - std::cerr << "Problem with AddSpaceBetweenCapitalizedWords " << '"' << test - << '"' << std::endl; - res = false; - } - - char* cres = - kwsys::SystemTools::AppendStrings("Mary Had A", " Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { - std::cerr << "Problem with AppendStrings " - << "\"Mary Had A\" \" Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - cres = kwsys::SystemTools::AppendStrings("Mary Had", " A ", "Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { - std::cerr << "Problem with AppendStrings " - << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.", 'a') != 3) { - std::cerr << "Problem with CountChar " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - cres = kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.", "aeiou"); - if (strcmp(cres, "Mry Hd A Lttl Lmb.")) { - std::cerr << "Problem with RemoveChars " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - cres = kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb."); - if (strcmp(cres, "A")) { - std::cerr << "Problem with RemoveCharsButUpperHex " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - char* cres2 = strdup("Mary Had A Little Lamb."); - kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X'); - if (strcmp(cres2, "MXry HXd A LXttlX LXmb.")) { - std::cerr << "Problem with ReplaceChars " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - free(cres2); - - if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.", - "Mary ")) { - std::cerr << "Problem with StringStartsWith " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.", - " Lamb.")) { - std::cerr << "Problem with StringEndsWith " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { - std::cerr << "Problem with DuplicateString " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - test = "Mary Had A Little Lamb."; - if (kwsys::SystemTools::CropString(test, 13) != "Mary ...Lamb.") { - std::cerr << "Problem with CropString " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - std::vector lines; - kwsys::SystemTools::Split("Mary Had A Little Lamb.", lines, ' '); - if (lines[0] != "Mary" || lines[1] != "Had" || lines[2] != "A" || - lines[3] != "Little" || lines[4] != "Lamb.") { - std::cerr << "Problem with Split " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - if (kwsys::SystemTools::ConvertToWindowsOutputPath( - "L://Local Mojo/Hex Power Pack/Iffy Voodoo") != - "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { - std::cerr << "Problem with ConvertToWindowsOutputPath " - << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; - res = false; - } - - if (kwsys::SystemTools::ConvertToWindowsOutputPath( - "//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") != - "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { - std::cerr << "Problem with ConvertToWindowsOutputPath " - << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\"" - << std::endl; - res = false; - } - - if (kwsys::SystemTools::ConvertToUnixOutputPath( - "//Local Mojo/Hex Power Pack/Iffy Voodoo") != - "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo") { - std::cerr << "Problem with ConvertToUnixOutputPath " - << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; - res = false; - } - - return res; -} - -static bool CheckPutEnv(const std::string& env, const char* name, - const char* value) -{ - if (!kwsys::SystemTools::PutEnv(env)) { - std::cerr << "PutEnv(\"" << env << "\") failed!" << std::endl; - return false; - } - std::string v = "(null)"; - kwsys::SystemTools::GetEnv(name, v); - if (v != value) { - std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not \"" - << value << "\"!" << std::endl; - return false; - } - return true; -} - -static bool CheckUnPutEnv(const char* env, const char* name) -{ - if (!kwsys::SystemTools::UnPutEnv(env)) { - std::cerr << "UnPutEnv(\"" << env << "\") failed!" << std::endl; - return false; - } - std::string v; - if (kwsys::SystemTools::GetEnv(name, v)) { - std::cerr << "GetEnv(\"" << name << "\") returned \"" << v - << "\", not (null)!" << std::endl; - return false; - } - return true; -} - -static bool CheckEnvironmentOperations() -{ - bool res = true; - res &= CheckPutEnv("A=B", "A", "B"); - res &= CheckPutEnv("B=C", "B", "C"); - res &= CheckPutEnv("C=D", "C", "D"); - res &= CheckPutEnv("D=E", "D", "E"); - res &= CheckUnPutEnv("A", "A"); - res &= CheckUnPutEnv("B=", "B"); - res &= CheckUnPutEnv("C=D", "C"); - /* Leave "D=E" in environment so a memory checker can test for leaks. */ - return res; -} - -static bool CheckRelativePath(const std::string& local, - const std::string& remote, - const std::string& expected) -{ - std::string result = kwsys::SystemTools::RelativePath(local, remote); - if (!kwsys::SystemTools::ComparePath(expected, result)) { - std::cerr << "RelativePath(" << local << ", " << remote << ") yielded " - << result << " instead of " << expected << std::endl; - return false; - } - return true; -} - -static bool CheckRelativePaths() -{ - bool res = true; - res &= CheckRelativePath("/usr/share", "/bin/bash", "../../bin/bash"); - res &= CheckRelativePath("/usr/./share/", "/bin/bash", "../../bin/bash"); - res &= CheckRelativePath("/usr//share/", "/bin/bash", "../../bin/bash"); - res &= - CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash"); - res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin"); - return res; -} - -static bool CheckCollapsePath(const std::string& path, - const std::string& expected) -{ - std::string result = kwsys::SystemTools::CollapseFullPath(path); - if (!kwsys::SystemTools::ComparePath(expected, result)) { - std::cerr << "CollapseFullPath(" << path << ") yielded " << result - << " instead of " << expected << std::endl; - return false; - } - return true; -} - -static bool CheckCollapsePath() -{ - bool res = true; - res &= CheckCollapsePath("/usr/share/*", "/usr/share/*"); - res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*"); - res &= CheckCollapsePath("/usr/share/../lib", "/usr/lib"); - res &= CheckCollapsePath("/usr/share/./lib", "/usr/share/lib"); - res &= CheckCollapsePath("/usr/share/../../lib", "/lib"); - res &= CheckCollapsePath("/usr/share/.././../lib", "/lib"); - res &= CheckCollapsePath("/../lib", "/lib"); - res &= CheckCollapsePath("/../lib/", "/lib"); - res &= CheckCollapsePath("/", "/"); - res &= CheckCollapsePath("C:/", "C:/"); - res &= CheckCollapsePath("C:/../", "C:/"); - res &= CheckCollapsePath("C:/../../", "C:/"); - return res; -} - -static std::string StringVectorToString(const std::vector& vec) -{ - std::stringstream ss; - ss << "vector("; - for (std::vector::const_iterator i = vec.begin(); - i != vec.end(); ++i) { - if (i != vec.begin()) { - ss << ", "; - } - ss << *i; - } - ss << ")"; - return ss.str(); -} - -static bool CheckGetPath() -{ - const char* envName = "S"; -#ifdef _WIN32 - const char* envValue = "C:\\Somewhere\\something;D:\\Temp"; -#else - const char* envValue = "/Somewhere/something:/tmp"; -#endif - const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]"; - - std::vector originalPaths; - originalPaths.push_back(registryPath); - - std::vector expectedPaths; - expectedPaths.push_back(registryPath); -#ifdef _WIN32 - expectedPaths.push_back("C:/Somewhere/something"); - expectedPaths.push_back("D:/Temp"); -#else - expectedPaths.push_back("/Somewhere/something"); - expectedPaths.push_back("/tmp"); -#endif - - bool res = true; - res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue); - - std::vector paths = originalPaths; - kwsys::SystemTools::GetPath(paths, envName); - - if (paths != expectedPaths) { - std::cerr << "GetPath(" << StringVectorToString(originalPaths) << ", " - << envName << ") yielded " << StringVectorToString(paths) - << " instead of " << StringVectorToString(expectedPaths) - << std::endl; - res = false; - } - - res &= CheckUnPutEnv(envName, envName); - return res; -} - -static bool CheckGetFilenameName() -{ - const char* windowsFilepath = "C:\\somewhere\\something"; - const char* unixFilepath = "/somewhere/something"; - -#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) - std::string expectedWindowsFilename = "something"; -#else - std::string expectedWindowsFilename = "C:\\somewhere\\something"; -#endif - std::string expectedUnixFilename = "something"; - - bool res = true; - std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath); - if (filename != expectedWindowsFilename) { - std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded " - << filename << " instead of " << expectedWindowsFilename - << std::endl; - res = false; - } - - filename = kwsys::SystemTools::GetFilenameName(unixFilepath); - if (filename != expectedUnixFilename) { - std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename - << " instead of " << expectedUnixFilename << std::endl; - res = false; - } - return res; -} - -static bool CheckFind() -{ - bool res = true; - const std::string testFindFileName("testFindFile.txt"); - const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/" + - testFindFileName); - - if (!kwsys::SystemTools::Touch(testFindFile.c_str(), true)) { - std::cerr << "Problem with Touch for: " << testFindFile << std::endl; - // abort here as the existence of the file only makes the test meaningful - return false; - } - - std::vector searchPaths; - searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR); - if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true) - .empty()) { - std::cerr << "Problem with FindFile without system paths for: " - << testFindFileName << std::endl; - res = false; - } - if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, false) - .empty()) { - std::cerr << "Problem with FindFile with system paths for: " - << testFindFileName << std::endl; - res = false; - } - - return res; -} - -static bool CheckIsSubDirectory() -{ - bool res = true; - - if (kwsys::SystemTools::IsSubDirectory("/foo", "/") == false) { - std::cerr << "Problem with IsSubDirectory (root - unix): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("c:/foo", "c:/") == false) { - std::cerr << "Problem with IsSubDirectory (root - dos): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("/foo/bar", "/foo") == false) { - std::cerr << "Problem with IsSubDirectory (deep): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("/foo", "/foo") == true) { - std::cerr << "Problem with IsSubDirectory (identity): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("/fooo", "/foo") == true) { - std::cerr << "Problem with IsSubDirectory (substring): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("/foo/", "/foo") == true) { - std::cerr << "Problem with IsSubDirectory (prepended slash): " - << std::endl; - res = false; - } - - return res; -} - -static bool CheckGetLineFromStream() -{ - const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR - "/README.rst"); - - kwsys::ifstream file(fileWithFiveCharsOnFirstLine.c_str(), std::ios::in); - - if (!file) { - std::cerr << "Problem opening: " << fileWithFiveCharsOnFirstLine - << std::endl; - return false; - } - - std::string line; - bool has_newline = false; - bool result; - - file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); - if (!result || line.size() != 5) { - std::cerr << "First line does not have five characters: " << line.size() - << std::endl; - return false; - } - - file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); - if (!result || line.size() != 5) { - std::cerr << "First line does not have five characters after rewind: " - << line.size() << std::endl; - return false; - } - - bool ret = true; - - for (size_t size = 1; size <= 5; ++size) { - file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, - static_cast(size)); - if (!result || line.size() != size) { - std::cerr << "Should have read " << size << " characters but got " - << line.size() << std::endl; - ret = false; - } - } - - return ret; -} - -int testSystemTools(int, char* []) -{ - bool res = true; - - int cc; - for (cc = 0; toUnixPaths[cc][0]; cc++) { - res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]); - } - - // Special check for ~ - std::string output; - if (kwsys::SystemTools::GetEnv("HOME", output)) { - output += "/foo bar/lala"; - res &= CheckConvertToUnixSlashes("~/foo bar/lala", output); - } - - for (cc = 0; checkEscapeChars[cc][0]; cc++) { - res &= CheckEscapeChars(checkEscapeChars[cc][0], checkEscapeChars[cc][1], - *checkEscapeChars[cc][2], checkEscapeChars[cc][3]); - } - - res &= CheckFileOperations(); - - res &= CheckStringOperations(); - - res &= CheckEnvironmentOperations(); - - res &= CheckRelativePaths(); - - res &= CheckCollapsePath(); - - res &= CheckGetPath(); - - res &= CheckFind(); - - res &= CheckIsSubDirectory(); - - res &= CheckGetLineFromStream(); - - res &= CheckGetFilenameName(); - - return res ? 0 : 1; -} diff --git a/thirdparty/KWSys/adios2sys/testSystemTools.h.in b/thirdparty/KWSys/adios2sys/testSystemTools.h.in deleted file mode 100644 index 022e36e2f4..0000000000 --- a/thirdparty/KWSys/adios2sys/testSystemTools.h.in +++ /dev/null @@ -1,12 +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@_testSystemtools_h -#define @KWSYS_NAMESPACE@_testSystemtools_h - -#define EXECUTABLE_OUTPUT_PATH "@CMAKE_CURRENT_BINARY_DIR@" - -#define TEST_SYSTEMTOOLS_SOURCE_DIR "@TEST_SYSTEMTOOLS_SOURCE_DIR@" -#define TEST_SYSTEMTOOLS_BINARY_DIR "@TEST_SYSTEMTOOLS_BINARY_DIR@" -#cmakedefine KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS - -#endif diff --git a/thirdparty/KWSys/adios2sys/testTerminal.c b/thirdparty/KWSys/adios2sys/testTerminal.c deleted file mode 100644 index f6c1eddb7b..0000000000 --- a/thirdparty/KWSys/adios2sys/testTerminal.c +++ /dev/null @@ -1,22 +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 - -int testTerminal(int argc, char* argv[]) -{ - (void)argc; - (void)argv; - kwsysTerminal_cfprintf(kwsysTerminal_Color_ForegroundYellow | - kwsysTerminal_Color_BackgroundBlue | - kwsysTerminal_Color_AssumeTTY, - stdout, "Hello %s!", "World"); - fprintf(stdout, "\n"); - return 0; -} From 1fa26e6df5e4ca9a81b1c3226910ab3bb3c17f71 Mon Sep 17 00:00:00 2001 From: KWSys Upstream Date: Tue, 29 Sep 2020 05:21:34 -0400 Subject: [PATCH 03/17] KWSys 2020-09-29 (4a19ed43) Code extracted from: https://gitlab.kitware.com/utils/kwsys.git at commit 4a19ed432e73d9720244eb52799c4c0a54172eca (master). --- .gitattributes | 25 + Base64.c | 228 ++ Base64.h.in | 110 + CMakeLists.txt | 1143 +++++++ CONTRIBUTING.rst | 49 + CTestConfig.cmake | 11 + CTestCustom.cmake.in | 18 + CommandLineArguments.cxx | 760 +++++ CommandLineArguments.hxx.in | 270 ++ Configure.h.in | 81 + Configure.hxx.in | 65 + ConsoleBuf.hxx.in | 398 +++ Copyright.txt | 38 + Directory.cxx | 255 ++ Directory.hxx.in | 75 + DynamicLoader.cxx | 473 +++ DynamicLoader.hxx.in | 106 + Encoding.h.in | 69 + Encoding.hxx.in | 80 + EncodingC.c | 72 + EncodingCXX.cxx | 288 ++ ExtraTest.cmake.in | 1 + FStream.cxx | 55 + FStream.hxx.in | 282 ++ Glob.cxx | 456 +++ Glob.hxx.in | 135 + MD5.c | 504 +++ MD5.h.in | 97 + Process.h.in | 544 ++++ ProcessUNIX.c | 2929 ++++++++++++++++++ ProcessWin32.c | 2777 +++++++++++++++++ README.rst | 37 + RegularExpression.cxx | 1217 ++++++++ RegularExpression.hxx.in | 567 ++++ SharedForward.h.in | 873 ++++++ String.c | 100 + String.h.in | 57 + String.hxx.in | 57 + System.c | 236 ++ System.h.in | 60 + SystemInformation.cxx | 5471 +++++++++++++++++++++++++++++++++ SystemInformation.hxx.in | 163 + SystemTools.cxx | 4694 ++++++++++++++++++++++++++++ SystemTools.hxx.in | 983 ++++++ Terminal.c | 423 +++ Terminal.h.in | 170 + kwsysHeaderDump.pl | 41 + kwsysPlatformTests.cmake | 216 ++ kwsysPlatformTestsC.c | 71 + kwsysPlatformTestsCXX.cxx | 174 ++ kwsysPrivate.h | 34 + testCommandLineArguments.cxx | 209 ++ testCommandLineArguments1.cxx | 91 + testConfigure.cxx | 30 + testConsoleBuf.cxx | 782 +++++ testConsoleBuf.hxx | 17 + testConsoleBufChild.cxx | 55 + testDirectory.cxx | 143 + testDynamicLoader.cxx | 133 + testDynload.c | 13 + testDynloadImpl.c | 10 + testDynloadImpl.h | 15 + testDynloadUse.c | 15 + testEncode.c | 67 + testEncoding.cxx | 285 ++ testFStream.cxx | 110 + testFail.c | 24 + testProcess.c | 726 +++++ testSharedForward.c.in | 27 + testSystemInformation.cxx | 90 + testSystemTools.bin | Bin 0 -> 766 bytes testSystemTools.cxx | 1233 ++++++++ testSystemTools.h.in | 12 + testTerminal.c | 22 + 74 files changed, 32147 insertions(+) create mode 100644 .gitattributes create mode 100644 Base64.c create mode 100644 Base64.h.in create mode 100644 CMakeLists.txt create mode 100644 CONTRIBUTING.rst create mode 100644 CTestConfig.cmake create mode 100644 CTestCustom.cmake.in create mode 100644 CommandLineArguments.cxx create mode 100644 CommandLineArguments.hxx.in create mode 100644 Configure.h.in create mode 100644 Configure.hxx.in create mode 100644 ConsoleBuf.hxx.in create mode 100644 Copyright.txt create mode 100644 Directory.cxx create mode 100644 Directory.hxx.in create mode 100644 DynamicLoader.cxx create mode 100644 DynamicLoader.hxx.in create mode 100644 Encoding.h.in create mode 100644 Encoding.hxx.in create mode 100644 EncodingC.c create mode 100644 EncodingCXX.cxx create mode 100644 ExtraTest.cmake.in create mode 100644 FStream.cxx create mode 100644 FStream.hxx.in create mode 100644 Glob.cxx create mode 100644 Glob.hxx.in create mode 100644 MD5.c create mode 100644 MD5.h.in create mode 100644 Process.h.in create mode 100644 ProcessUNIX.c create mode 100644 ProcessWin32.c create mode 100644 README.rst create mode 100644 RegularExpression.cxx create mode 100644 RegularExpression.hxx.in create mode 100644 SharedForward.h.in create mode 100644 String.c create mode 100644 String.h.in create mode 100644 String.hxx.in create mode 100644 System.c create mode 100644 System.h.in create mode 100644 SystemInformation.cxx create mode 100644 SystemInformation.hxx.in create mode 100644 SystemTools.cxx create mode 100644 SystemTools.hxx.in create mode 100644 Terminal.c create mode 100644 Terminal.h.in create mode 100755 kwsysHeaderDump.pl create mode 100644 kwsysPlatformTests.cmake create mode 100644 kwsysPlatformTestsC.c create mode 100644 kwsysPlatformTestsCXX.cxx create mode 100644 kwsysPrivate.h create mode 100644 testCommandLineArguments.cxx create mode 100644 testCommandLineArguments1.cxx create mode 100644 testConfigure.cxx create mode 100644 testConsoleBuf.cxx create mode 100644 testConsoleBuf.hxx create mode 100644 testConsoleBufChild.cxx create mode 100644 testDirectory.cxx create mode 100644 testDynamicLoader.cxx create mode 100644 testDynload.c create mode 100644 testDynloadImpl.c create mode 100644 testDynloadImpl.h create mode 100644 testDynloadUse.c create mode 100644 testEncode.c create mode 100644 testEncoding.cxx create mode 100644 testFStream.cxx create mode 100644 testFail.c create mode 100644 testProcess.c create mode 100644 testSharedForward.c.in create mode 100644 testSystemInformation.cxx create mode 100644 testSystemTools.bin create mode 100644 testSystemTools.cxx create mode 100644 testSystemTools.h.in create mode 100644 testTerminal.c diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..b4e6160fda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,25 @@ +.git* export-ignore +# import off +.gitattributes -export-ignore +.hooks* export-ignore + +# Custom attribute to mark sources as using the kwsys C code style. +[attr]kwsys-c-style whitespace=tab-in-indent format.clang-format + +/GitSetup export-ignore +/*.sh export-ignore eol=lf +/*.bash export-ignore eol=lf +/.clang-format export-ignore +# import on + +*.c kwsys-c-style +*.c.in kwsys-c-style +*.cxx kwsys-c-style +*.h kwsys-c-style +*.h.in kwsys-c-style +*.hxx kwsys-c-style +*.hxx.in kwsys-c-style + +*.cmake whitespace=tab-in-indent +*.rst whitespace=tab-in-indent conflict-marker-size=79 +*.txt whitespace=tab-in-indent diff --git a/Base64.c b/Base64.c new file mode 100644 index 0000000000..42650184a5 --- /dev/null +++ b/Base64.c @@ -0,0 +1,228 @@ +/* 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; + unsigned char d1; + unsigned char d2; + unsigned char d3; + + d0 = kwsysBase64DecodeChar(src[0]); + d1 = kwsysBase64DecodeChar(src[1]); + d2 = kwsysBase64DecodeChar(src[2]); + d3 = kwsysBase64DecodeChar(src[3]); + + /* Make sure all characters were valid */ + + if (d0 == 0xFF || d1 == 0xFF || d2 == 0xFF || d3 == 0xFF) { + return 0; + } + + /* Decode the 3 bytes */ + + dest[0] = (unsigned char)(((d0 << 2) & 0xFC) | ((d1 >> 4) & 0x03)); + dest[1] = (unsigned char)(((d1 << 4) & 0xF0) | ((d2 >> 2) & 0x0F)); + dest[2] = (unsigned char)(((d2 << 6) & 0xC0) | ((d3 >> 0) & 0x3F)); + + /* Return the number of bytes actually decoded */ + + if (src[2] == '=') { + return 1; + } + if (src[3] == '=') { + return 2; + } + return 3; +} + +/* Decode bytes from the input buffer and store the decoded stream + into the output buffer until 'length' bytes have been decoded. Return the + real length of the decoded stream (which should be equal to 'length'). Note + that the output buffer must be allocated by the caller. If + 'max_input_length' is not null, then it specifies the number of encoded + bytes that should be at most read from the input buffer. In that case the + 'length' parameter is ignored. This enables the caller to decode a stream + without actually knowing how much decoded data to expect (of course, the + buffer must be large enough). */ +size_t kwsysBase64_Decode(const unsigned char* input, size_t length, + unsigned char* output, size_t max_input_length) +{ + const unsigned char* ptr = input; + unsigned char* optr = output; + + /* Decode complete triplet */ + + if (max_input_length) { + const unsigned char* end = input + max_input_length; + while (ptr < end) { + int len = kwsysBase64_Decode3(ptr, optr); + optr += len; + if (len < 3) { + return (size_t)(optr - output); + } + ptr += 4; + } + } else { + unsigned char* oend = output + length; + while ((oend - optr) >= 3) { + int len = kwsysBase64_Decode3(ptr, optr); + optr += len; + if (len < 3) { + return (size_t)(optr - output); + } + ptr += 4; + } + + /* Decode the last triplet */ + + if (oend - optr == 2) { + unsigned char temp[3]; + int len = kwsysBase64_Decode3(ptr, temp); + if (len >= 2) { + optr[0] = temp[0]; + optr[1] = temp[1]; + optr += 2; + } else if (len > 0) { + optr[0] = temp[0]; + optr += 1; + } + } else if (oend - optr == 1) { + unsigned char temp[3]; + int len = kwsysBase64_Decode3(ptr, temp); + if (len > 0) { + optr[0] = temp[0]; + optr += 1; + } + } + } + + return (size_t)(optr - output); +} diff --git a/Base64.h.in b/Base64.h.in new file mode 100644 index 0000000000..729f972978 --- /dev/null +++ b/Base64.h.in @@ -0,0 +1,110 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Base64_h +#define @KWSYS_NAMESPACE@_Base64_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include /* size_t */ + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysBase64 kwsys_ns(Base64) +# define kwsysBase64_Decode kwsys_ns(Base64_Decode) +# define kwsysBase64_Decode3 kwsys_ns(Base64_Decode3) +# define kwsysBase64_Encode kwsys_ns(Base64_Encode) +# define kwsysBase64_Encode1 kwsys_ns(Base64_Encode1) +# define kwsysBase64_Encode2 kwsys_ns(Base64_Encode2) +# define kwsysBase64_Encode3 kwsys_ns(Base64_Encode3) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Encode 3 bytes into a 4 byte string. + */ +kwsysEXPORT void kwsysBase64_Encode3(const unsigned char* src, + unsigned char* dest); + +/** + * Encode 2 bytes into a 4 byte string. + */ +kwsysEXPORT void kwsysBase64_Encode2(const unsigned char* src, + unsigned char* dest); + +/** + * Encode 1 bytes into a 4 byte string. + */ +kwsysEXPORT void kwsysBase64_Encode1(const unsigned char* src, + unsigned char* dest); + +/** + * Encode 'length' bytes from the input buffer and store the encoded + * stream into the output buffer. Return the length of the encoded + * buffer (output). Note that the output buffer must be allocated by + * the caller (length * 1.5 should be a safe estimate). If 'mark_end' + * is true than an extra set of 4 bytes is added to the end of the + * stream if the input is a multiple of 3 bytes. These bytes are + * invalid chars and therefore they will stop the decoder thus + * enabling the caller to decode a stream without actually knowing how + * much data to expect (if the input is not a multiple of 3 bytes then + * the extra padding needed to complete the encode 4 bytes will stop + * the decoding anyway). + */ +kwsysEXPORT size_t kwsysBase64_Encode(const unsigned char* input, + size_t length, unsigned char* output, + int mark_end); + +/** + * Decode 4 bytes into a 3 byte string. Returns the number of bytes + * actually decoded. + */ +kwsysEXPORT int kwsysBase64_Decode3(const unsigned char* src, + unsigned char* dest); + +/** + * Decode bytes from the input buffer and store the decoded stream + * into the output buffer until 'length' bytes have been decoded. + * Return the real length of the decoded stream (which should be equal + * to 'length'). Note that the output buffer must be allocated by the + * caller. If 'max_input_length' is not null, then it specifies the + * number of encoded bytes that should be at most read from the input + * buffer. In that case the 'length' parameter is ignored. This + * enables the caller to decode a stream without actually knowing how + * much decoded data to expect (of course, the buffer must be large + * enough). + */ +kwsysEXPORT size_t kwsysBase64_Decode(const unsigned char* input, + size_t length, unsigned char* output, + size_t max_input_length); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysBase64 +# undef kwsysBase64_Decode +# undef kwsysBase64_Decode3 +# undef kwsysBase64_Encode +# undef kwsysBase64_Encode1 +# undef kwsysBase64_Encode2 +# undef kwsysBase64_Encode3 +# endif +#endif + +#endif diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..b0a8542929 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,1143 @@ +# 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. +# add_subdirectory(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 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_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. + +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_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() + 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(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 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) + +# Add selected C++ classes. +set(cppclasses + Directory DynamicLoader Encoding Glob RegularExpression SystemTools + CommandLineArguments 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_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 + $) + if(KWSYS_INSTALL_INCLUDE_DIR) + target_include_directories(${KWSYS_TARGET_INTERFACE} INTERFACE + $) + 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 + $) + 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 + $) + if(KWSYS_INSTALL_INCLUDE_DIR) + target_include_directories(${KWSYS_TARGET_C_INTERFACE} INTERFACE + $) + 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(CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(EXEC_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + 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 + 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}) + #set(KWSYS_TEST_PROCESS_7 7) # uncomment to run timing-sensitive test locally + 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() diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000000..32e7b83c5b --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,49 @@ +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 diff --git a/CTestConfig.cmake b/CTestConfig.cmake new file mode 100644 index 0000000000..99d197ebcf --- /dev/null +++ b/CTestConfig.cmake @@ -0,0 +1,11 @@ +# 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") +if (NOT CTEST_DROP_METHOD STREQUAL "https") + set(CTEST_DROP_METHOD "http") +endif () +set(CTEST_DROP_SITE "open.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=KWSys") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in new file mode 100644 index 0000000000..c07f0f30f8 --- /dev/null +++ b/CTestCustom.cmake.in @@ -0,0 +1,18 @@ +# 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 + ) + +list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION + "LICENSE WARNING" + ) diff --git a/CommandLineArguments.cxx b/CommandLineArguments.cxx new file mode 100644 index 0000000000..e45db36ac2 --- /dev/null +++ b/CommandLineArguments.cxx @@ -0,0 +1,760 @@ +/* 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 +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _MSC_VER +# pragma warning(disable : 4786) +#endif + +#if defined(__sgi) && !defined(__GNUC__) +# pragma set woff 1375 /* base class destructor not virtual */ +#endif + +#if 0 +# define CommandLineArguments_DEBUG(x) \ + 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 +{ +}; +class CommandLineArgumentsSetOfStrings : public std::set +{ +}; +class CommandLineArgumentsMapOfStrucs + : public std::map +{ +}; + +class CommandLineArgumentsInternal +{ +public: + CommandLineArgumentsInternal() = default; + + using VectorOfStrings = CommandLineArgumentsVectorOfStrings; + using CallbacksMap = CommandLineArgumentsMapOfStrucs; + using String = kwsys::String; + using SetOfStrings = CommandLineArgumentsSetOfStrings; + + VectorOfStrings Argv; + String Argv0; + CallbacksMap Callbacks; + + CommandLineArguments::ErrorCallbackType UnknownArgumentCallback{ nullptr }; + void* ClientData{ nullptr }; + + VectorOfStrings::size_type LastArgument{ 0 }; + + VectorOfStrings UnusedArguments; +}; + +CommandLineArguments::CommandLineArguments() +{ + this->Internals = new CommandLineArguments::Internal; + this->Help = ""; + this->LineLength = 80; + this->StoreUnusedArgumentsFlag = false; +} + +CommandLineArguments::~CommandLineArguments() +{ + delete this->Internals; +} + +void CommandLineArguments::Initialize(int argc, const char* const argv[]) +{ + int cc; + + this->Initialize(); + this->Internals->Argv0 = argv[0]; + for (cc = 1; cc < argc; cc++) { + this->ProcessArgument(argv[cc]); + } +} + +void CommandLineArguments::Initialize(int argc, char* argv[]) +{ + this->Initialize(argc, static_cast(argv)); +} + +void CommandLineArguments::Initialize() +{ + this->Internals->Argv.clear(); + this->Internals->LastArgument = 0; +} + +void CommandLineArguments::ProcessArgument(const char* arg) +{ + this->Internals->Argv.push_back(arg); +} + +bool CommandLineArguments::GetMatchedArguments( + std::vector* 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::size_type cc; + std::vector 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) +CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, std::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, std::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING, + std::vector) +#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) +{ + auto 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 (;;) { + auto hit = this->Internals->Callbacks.find(cs->Help); + if (hit == this->Internals->Callbacks.end()) { + break; + } + cs = &(hit->second); + } + return cs->Help; +} + +void CommandLineArguments::SetLineLength(unsigned int ll) +{ + if (ll < 9 || ll > 1000) { + return; + } + this->LineLength = ll; + this->GenerateHelp(); +} + +const char* CommandLineArguments::GetArgv0() +{ + return this->Internals->Argv0.c_str(); +} + +unsigned int CommandLineArguments::GetLastArgument() +{ + return static_cast(this->Internals->LastArgument + 1); +} + +void CommandLineArguments::GenerateHelp() +{ + std::ostringstream str; + + // Collapse all arguments into the map of vectors of all arguments that do + // the same thing. + CommandLineArguments::Internal::CallbacksMap::iterator it; + using MapArgs = std::map; + 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(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(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* 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* variable, + const std::string& value) +{ + char* res = nullptr; + variable->push_back(static_cast(strtol(value.c_str(), &res, 10))); + // if ( res && *res ) + // { + // Can handle non-int + // } +} + +void CommandLineArguments::PopulateVariable(std::vector* 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* 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* 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 false; + } + } + 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(cs->Variable), var); + break; + case CommandLineArguments::DOUBLE_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::STRING_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::STL_STRING_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::BOOL_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::VECTOR_BOOL_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), + var); + break; + case CommandLineArguments::VECTOR_INT_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), + var); + break; + case CommandLineArguments::VECTOR_DOUBLE_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), + var); + break; + case CommandLineArguments::VECTOR_STRING_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), + var); + break; + case CommandLineArguments::VECTOR_STL_STRING_TYPE: + this->PopulateVariable( + static_cast*>(cs->Variable), var); + break; + default: + std::cerr << "Got unknown variable type: \"" << cs->VariableType + << "\"" << std::endl; + this->Internals->LastArgument--; + return false; + } + } + return true; +} + +} // namespace KWSYS_NAMESPACE diff --git a/CommandLineArguments.hxx.in b/CommandLineArguments.hxx.in new file mode 100644 index 0000000000..7db9015564 --- /dev/null +++ b/CommandLineArguments.hxx.in @@ -0,0 +1,270 @@ +/* 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 +#include + +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* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + + /** + * Add handler for boolean argument. The argument does not take any option + * and if it is specified, the value of the variable is true/1, otherwise it + * is false/0. + */ + void AddBooleanArgument(const char* argument, bool* variable, + const char* help); + void AddBooleanArgument(const char* argument, int* variable, + const char* help); + void AddBooleanArgument(const char* argument, double* variable, + const char* help); + void AddBooleanArgument(const char* argument, char** variable, + const char* help); + void AddBooleanArgument(const char* argument, 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* 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* variable, const std::string& value); + void PopulateVariable(std::vector* variable, const std::string& value); + void PopulateVariable(std::vector* variable, + const std::string& value); + void PopulateVariable(std::vector* variable, + const std::string& value); + void PopulateVariable(std::vector* variable, + const std::string& value); + + typedef CommandLineArgumentsInternal Internal; + Internal* Internals; + std::string Help; + + unsigned int LineLength; + + bool StoreUnusedArgumentsFlag; +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/Configure.h.in b/Configure.h.in new file mode 100644 index 0000000000..8a237cea31 --- /dev/null +++ b/Configure.h.in @@ -0,0 +1,81 @@ +/* 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(__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 +#endif + +/* MSVC 6.0 in release mode will warn about code it produces with its + optimizer. Disable the warnings specifically for this + configuration. Real warnings will be revealed by a debug build or + by other compilers. */ +#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE_BOGUS) +# if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG) +# pragma warning(disable : 4701) /* Variable may be used uninitialized. */ +# pragma warning(disable : 4702) /* Unreachable code. */ +# endif +#endif + +#endif diff --git a/Configure.hxx.in b/Configure.hxx.in new file mode 100644 index 0000000000..29a2dd11e3 --- /dev/null +++ b/Configure.hxx.in @@ -0,0 +1,65 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_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 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(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 diff --git a/ConsoleBuf.hxx.in b/ConsoleBuf.hxx.in new file mode 100644 index 0000000000..49dbdf7ea5 --- /dev/null +++ b/ConsoleBuf.hxx.in @@ -0,0 +1,398 @@ +/* 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 +#include +#include +#include +#include +#include + +#if defined(_WIN32) +# include +# if __cplusplus >= 201103L +# include +# endif +#endif + +namespace @KWSYS_NAMESPACE@ { +#if defined(_WIN32) + +template > +class BasicConsoleBuf : public std::basic_streambuf +{ +public: + typedef typename Traits::int_type int_type; + typedef typename Traits::char_type char_type; + + class Manager + { + public: + Manager(std::basic_ios& ios, const bool err = false) + : m_consolebuf(0) + { + m_ios = &ios; + try { + m_consolebuf = new BasicConsoleBuf(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* 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* m_ios; + std::basic_streambuf* m_streambuf; + BasicConsoleBuf* 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 m_ibuffer; + std::basic_string 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(MultiByteToWideChar( + actualCodepage, 0, data, static_cast(length), nullptr, 0)); + wchar_t* wbuf = new wchar_t[wlength]; + const bool success = + MultiByteToWideChar(actualCodepage, 0, data, static_cast(length), + wbuf, static_cast(wlength)) > 0 + ? true + : false; + wbuffer = std::wstring(wbuf, wlength); + delete[] wbuf; + return success; + } + std::wstring getBuffer(const std::basic_string buffer) + { + return Encoding::ToWide(buffer); + } + std::wstring getBuffer(const std::basic_string buffer) + { + return buffer; + } + void setBuffer(const std::wstring wbuffer, std::basic_string& target) + { + target = Encoding::ToNarrow(wbuffer); + } + void setBuffer(const std::wstring wbuffer, + std::basic_string& target) + { + target = wbuffer; + } + +}; // BasicConsoleBuf class + +typedef BasicConsoleBuf ConsoleBuf; +typedef BasicConsoleBuf WConsoleBuf; + +#endif +} // KWSYS_NAMESPACE + +#endif diff --git a/Copyright.txt b/Copyright.txt new file mode 100644 index 0000000000..33d7fb4726 --- /dev/null +++ b/Copyright.txt @@ -0,0 +1,38 @@ +KWSys - Kitware System Library +Copyright 2000-2016 Kitware, Inc. and Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Kitware, Inc. nor the names of Contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------ + +The following individuals and institutions are among the Contributors: + +* Insight Software Consortium + +See version control history for details of individual contributions. diff --git a/Directory.cxx b/Directory.cxx new file mode 100644 index 0000000000..0c2190aee5 --- /dev/null +++ b/Directory.cxx @@ -0,0 +1,255 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(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 +#include + +namespace KWSYS_NAMESPACE { + +class DirectoryInternals +{ +public: + // Array of Files + std::vector Files; + + // Path to Open'ed directory + std::string Path; +}; + +Directory::Directory() +{ + this->Internal = new DirectoryInternals; +} + +Directory::Directory(Directory&& other) +{ + this->Internal = other.Internal; + other.Internal = nullptr; +} + +Directory& Directory::operator=(Directory&& other) +{ + std::swap(this->Internal, other.Internal); + return *this; +} + +Directory::~Directory() +{ + delete this->Internal; +} + +unsigned long Directory::GetNumberOfFiles() const +{ + return static_cast(this->Internal->Files.size()); +} + +const char* Directory::GetFile(unsigned long dindex) const +{ + if (dindex >= this->Internal->Files.size()) { + return 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 + +# include +# include +# include +# include +# include +# include +# include +# include + +namespace KWSYS_NAMESPACE { + +bool Directory::Load(const std::string& name, std::string* errorMessage) +{ + this->Clear(); + intptr_t srchHandle; + 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((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(srchHandle, &data) != -1); + this->Internal->Path = name; + return _findclose(srchHandle) != -1; +} + +unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, + std::string* errorMessage) +{ + intptr_t srchHandle; + 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((wchar_t*)Encoding::ToWide(buf).c_str(), &data); + delete[] buf; + + if (srchHandle == -1) { + return 0; + } + + // Loop through names + unsigned long count = 0; + do { + count++; + } while (_wfindnext(srchHandle, &data) != -1); + _findclose(srchHandle); + return count; +} + +} // namespace KWSYS_NAMESPACE + +#else + +// Now the POSIX style directory access + +# include + +# include +# include +# include + +// 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, std::string* errorMessage) +{ + this->Clear(); + + errno = 0; + DIR* dir = opendir(name.c_str()); + + if (!dir) { + if (errorMessage != nullptr) { + *errorMessage = std::string(strerror(errno)); + } + return false; + } + + errno = 0; + for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { + this->Internal->Files.emplace_back(d->d_name); + } + if (errno != 0) { + if (errorMessage != nullptr) { + *errorMessage = std::string(strerror(errno)); + } + return false; + } + + this->Internal->Path = name; + closedir(dir); + return true; +} + +unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, + std::string* errorMessage) +{ + errno = 0; + DIR* dir = opendir(name.c_str()); + + if (!dir) { + if (errorMessage != nullptr) { + *errorMessage = std::string(strerror(errno)); + } + return 0; + } + + unsigned long count = 0; + for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { + count++; + } + if (errno != 0) { + if (errorMessage != nullptr) { + *errorMessage = std::string(strerror(errno)); + } + return false; + } + + closedir(dir); + return count; +} + +} // namespace KWSYS_NAMESPACE + +#endif diff --git a/Directory.hxx.in b/Directory.hxx.in new file mode 100644 index 0000000000..7bc9db024e --- /dev/null +++ b/Directory.hxx.in @@ -0,0 +1,75 @@ +/* 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 + +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(Directory&& other); + Directory(const Directory&) = delete; + Directory& operator=(const Directory&) = delete; + Directory& operator=(Directory&& other); + bool operator==(const Directory&) = delete; + ~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&, std::string* errorMessage = nullptr); + + /** + * 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&, std::string* errorMessage = nullptr); + + /** + * 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; +}; // End Class: Directory + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/DynamicLoader.cxx b/DynamicLoader.cxx new file mode 100644 index 0000000000..66ee9eafa7 --- /dev/null +++ b/DynamicLoader.cxx @@ -0,0 +1,473 @@ +/* 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 +#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 // 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 +# include + +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(&result); +} + +const char* DynamicLoader::LastError() +{ + // TODO: Need implementation with errno/strerror + /* If successful, shl_findsym returns an integer (int) value zero. If + * shl_findsym cannot find sym, it returns -1 and sets errno to zero. + * If any other errors occur, shl_findsym returns -1 and sets errno to one + * of these values (defined in ): + * ENOEXEC + * A format error was detected in the specified library. + * ENOSYM + * A symbol on which sym depends could not be found. + * EINVAL + * The specified handle is invalid. + */ + + if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) { + return strerror(errno); + } + // else + return 0; +} + +} // namespace KWSYS_NAMESPACE + +#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030) +// Implementation for Mac OS X 10.2.x and earlier +# include +# include // 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(&result); +} + +const char* DynamicLoader::LastError() +{ + return 0; +} + +} // namespace KWSYS_NAMESPACE + +#elif defined(_WIN32) && !defined(__CYGWIN__) +// Implementation for Windows win32 code but not cygwin +# include + +# include + +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. + // + // 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; + const char* rsym = sym.c_str(); + result = (void*)GetProcAddress(lib, rsym); + return *reinterpret_cast(&result); +} + +# 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 // for strerror() + +# include +# include + +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 +# include +# include +# include + +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 + +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 diff --git a/DynamicLoader.hxx.in b/DynamicLoader.hxx.in new file mode 100644 index 0000000000..539c742598 --- /dev/null +++ b/DynamicLoader.hxx.in @@ -0,0 +1,106 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_DynamicLoader_hxx +#define @KWSYS_NAMESPACE@_DynamicLoader_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include + +#if defined(__hpux) +# include +#elif defined(_WIN32) && !defined(__CYGWIN__) +# include +#elif defined(__APPLE__) +# include +# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 +# include +# endif +#elif defined(__BEOS__) +# include +#endif + +namespace @KWSYS_NAMESPACE@ { +/** \class DynamicLoader + * \brief Portable loading of dynamic libraries or dll's. + * + * DynamicLoader provides a portable interface to loading dynamic + * libraries or dll's into a process. + * + * Directory currently works with Windows, Apple, HP-UX and Unix (POSIX) + * operating systems + * + * \warning dlopen on *nix system works the following way: + * If filename contains a slash ("/"), then it is interpreted as a (relative + * or absolute) pathname. Otherwise, the dynamic linker searches for the + * library as follows : see ld.so(8) for further details): + * Whereas this distinction does not exist on Win32. Therefore ideally you + * should be doing full path to 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 diff --git a/Encoding.h.in b/Encoding.h.in new file mode 100644 index 0000000000..86a26692ab --- /dev/null +++ b/Encoding.h.in @@ -0,0 +1,69 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Encoding_h +#define @KWSYS_NAMESPACE@_Encoding_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysEncoding kwsys_ns(Encoding) +# define kwsysEncoding_mbstowcs kwsys_ns(Encoding_mbstowcs) +# define kwsysEncoding_DupToWide kwsys_ns(Encoding_DupToWide) +# define kwsysEncoding_wcstombs kwsys_ns(Encoding_wcstombs) +# define kwsysEncoding_DupToNarrow kwsys_ns(Encoding_DupToNarrow) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Convert a narrow string to a wide string. + On Windows, UTF-8 is assumed, and on other platforms, + the current locale is assumed. + */ +kwsysEXPORT size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* src, + size_t n); + +/* Convert a narrow string to a wide string. + This can return NULL if the conversion fails. */ +kwsysEXPORT wchar_t* kwsysEncoding_DupToWide(const char* src); + +/* Convert a wide string to a narrow string. + On Windows, UTF-8 is assumed, and on other platforms, + the current locale is assumed. */ +kwsysEXPORT size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* src, + size_t n); + +/* Convert a wide string to a narrow string. + This can return NULL if the conversion fails. */ +kwsysEXPORT char* kwsysEncoding_DupToNarrow(const wchar_t* str); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysEncoding +# undef kwsysEncoding_mbstowcs +# undef kwsysEncoding_DupToWide +# undef kwsysEncoding_wcstombs +# undef kwsysEncoding_DupToNarrow +# endif +#endif + +#endif diff --git a/Encoding.hxx.in b/Encoding.hxx.in new file mode 100644 index 0000000000..75a2d4d0f9 --- /dev/null +++ b/Encoding.hxx.in @@ -0,0 +1,80 @@ +/* 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 +#include + +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 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 diff --git a/EncodingC.c b/EncodingC.c new file mode 100644 index 0000000000..e12236afe5 --- /dev/null +++ b/EncodingC.c @@ -0,0 +1,72 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Encoding.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Encoding.h.in" +#endif + +#include + +#ifdef _WIN32 +# include +#endif + +size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* str, size_t n) +{ + if (str == 0) { + return (size_t)-1; + } +#ifdef _WIN32 + return MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest, + (int)n) - + 1; +#else + return mbstowcs(dest, str, n); +#endif +} + +wchar_t* kwsysEncoding_DupToWide(const char* str) +{ + wchar_t* ret = NULL; + size_t length = kwsysEncoding_mbstowcs(NULL, str, 0) + 1; + if (length > 0) { + ret = (wchar_t*)malloc((length) * sizeof(wchar_t)); + if (ret) { + ret[0] = 0; + kwsysEncoding_mbstowcs(ret, str, length); + } + } + return ret; +} + +size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* str, size_t n) +{ + if (str == 0) { + return (size_t)-1; + } +#ifdef _WIN32 + return WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest, + (int)n, NULL, NULL) - + 1; +#else + return wcstombs(dest, str, n); +#endif +} + +char* kwsysEncoding_DupToNarrow(const wchar_t* str) +{ + char* ret = NULL; + size_t length = kwsysEncoding_wcstombs(0, str, 0) + 1; + if (length > 0) { + ret = (char*)malloc(length); + if (ret) { + ret[0] = 0; + kwsysEncoding_wcstombs(ret, str, length); + } + } + return ret; +} diff --git a/EncodingCXX.cxx b/EncodingCXX.cxx new file mode 100644 index 0000000000..c68c73c8ea --- /dev/null +++ b/EncodingCXX.cxx @@ -0,0 +1,288 @@ +/* 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 +#include +#include + +#ifdef _MSC_VER +# pragma warning(disable : 4786) +#endif + +// Windows API. +#if defined(_WIN32) +# include + +# include +# include +#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 av1(ac); + std::vector 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(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 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 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 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(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 diff --git a/ExtraTest.cmake.in b/ExtraTest.cmake.in new file mode 100644 index 0000000000..4cec9e2950 --- /dev/null +++ b/ExtraTest.cmake.in @@ -0,0 +1 @@ +message("*** This message is generated by message inside a file that is included in DartTestfile.txt ***") diff --git a/FStream.cxx b/FStream.cxx new file mode 100644 index 0000000000..5e4133ac56 --- /dev/null +++ b/FStream.cxx @@ -0,0 +1,55 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(FStream.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "FStream.hxx.in" +#endif + +namespace KWSYS_NAMESPACE { +namespace FStream { + +BOM ReadBOM(std::istream& in) +{ + if (!in.good()) { + return BOM_None; + } + unsigned long orig = in.tellg(); + unsigned char bom[4]; + in.read(reinterpret_cast(bom), 2); + if (!in.good()) { + in.clear(); + in.seekg(orig); + return BOM_None; + } + if (bom[0] == 0xEF && bom[1] == 0xBB) { + in.read(reinterpret_cast(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(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(bom + 2), 2); + if (in.good() && bom[2] == 0x00 && bom[3] == 0x00) { + return BOM_UTF32LE; + } + in.seekg(p); + return BOM_UTF16LE; + } + in.clear(); + in.seekg(orig); + return BOM_None; +} + +} // FStream namespace +} // KWSYS_NAMESPACE diff --git a/FStream.hxx.in b/FStream.hxx.in new file mode 100644 index 0000000000..b424488920 --- /dev/null +++ b/FStream.hxx.in @@ -0,0 +1,282 @@ +/* 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 +#if defined(_WIN32) +# if !defined(_MSC_VER) && @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H +# include +# 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 +class basic_filebuf : public std::basic_filebuf +{ +# if _MSC_VER >= 1400 +public: + typedef std::basic_filebuf my_base_type; + basic_filebuf* open(char const* s, std::ios_base::openmode mode) + { + const std::wstring wstr = Encoding::ToWindowsExtendedPath(s); + return static_cast(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 > +class basic_efilebuf +{ +public: +# if defined(_MSC_VER) + typedef basic_filebuf internal_buffer_type; +# else + typedef __gnu_cxx::stdio_filebuf 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* ios, + basic_efilebuf* efilebuf) + { +# if !defined(_MSC_VER) + ios->rdbuf(efilebuf->buf_); +# else + static_cast(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 > +class basic_ifstream + : public std::basic_istream + , public basic_efilebuf +{ +public: + typedef typename basic_efilebuf::internal_buffer_type + internal_buffer_type; + typedef std::basic_istream internal_stream_type; + + basic_ifstream() + : internal_stream_type(new internal_buffer_type()) + { + this->buf_ = + static_cast(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_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); + } + + bool is_open() { return this->_is_open(); } + + void close() { this->_set_state(this->_close(), this, this); } + + using basic_efilebuf::_is_open; + + internal_buffer_type* rdbuf() const { return this->buf_; } + + ~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); } +}; + +template > +class basic_ofstream + : public std::basic_ostream + , public basic_efilebuf +{ + using basic_efilebuf::_is_open; + +public: + typedef typename basic_efilebuf::internal_buffer_type + internal_buffer_type; + typedef std::basic_ostream internal_stream_type; + + basic_ofstream() + : internal_stream_type(new internal_buffer_type()) + { + this->buf_ = + static_cast(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_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); } + + bool is_open() { return this->_is_open(); } + + internal_buffer_type* rdbuf() const { return this->buf_; } + + ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); } +}; + +typedef basic_ifstream ifstream; +typedef basic_ofstream ofstream; + +# undef @KWSYS_NAMESPACE@_FStream_NOEXCEPT +#else +using std::ofstream; +using std::ifstream; +#endif + +namespace FStream { +enum BOM +{ + BOM_None, + BOM_UTF8, + BOM_UTF16BE, + BOM_UTF16LE, + BOM_UTF32BE, + BOM_UTF32LE +}; + +// Read a BOM, if one exists. +// If a BOM exists, the stream is advanced to after the BOM. +// This function requires a seekable stream (but not a relative +// seekable stream). +@KWSYS_NAMESPACE@_EXPORT BOM ReadBOM(std::istream& in); +} +} + +#endif diff --git a/Glob.cxx b/Glob.cxx new file mode 100644 index 0000000000..c6d4b1985d --- /dev/null +++ b/Glob.cxx @@ -0,0 +1,456 @@ +/* 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 +#include +#include + +#include +#include +#include +namespace KWSYS_NAMESPACE { +#if defined(_WIN32) || defined(__APPLE__) +// 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 Files; + std::vector Expressions; +}; + +Glob::Glob() +{ + this->Internals = new GlobInternals; + this->Recurse = false; + this->Relative = ""; + + this->RecurseThroughSymlinks = true; + // RecurseThroughSymlinks is true by default for backwards compatibility, + // not because it's a good idea... + this->FollowedSymlinkCount = 0; + + // Keep separate variables for directory listing for back compatibility + this->ListDirs = true; + this->RecurseListDirs = false; +} + +Glob::~Glob() +{ + delete this->Internals; +} + +std::vector& 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(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; + std::string errorMessage; + if (!d.Load(dir, &errorMessage)) { + if (messages) { + if (!errorMessage.empty()) { + messages->push_back(Message(Glob::warning, + "Error listing directory '" + dir + + "'! Reason: '" + errorMessage + "'")); + } + } + 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::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) { + if (kwsys::SystemTools::FileIsDirectory(dir)) { + 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.erase(0, skip); + } + + 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(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.emplace_back(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& files, const std::string& file) +{ + if (!this->Relative.empty()) { + files.push_back(kwsys::SystemTools::RelativePath(this->Relative, file)); + } else { + files.push_back(file); + } +} + +} // namespace KWSYS_NAMESPACE diff --git a/Glob.hxx.in b/Glob.hxx.in new file mode 100644 index 0000000000..e8474e2001 --- /dev/null +++ b/Glob.hxx.in @@ -0,0 +1,135 @@ +/* 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 +#include + +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, + warning, + 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 GlobMessages; + typedef std::vector::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& 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& files, const std::string& file); + + GlobInternals* Internals; + bool Recurse; + std::string Relative; + bool RecurseThroughSymlinks; + unsigned int FollowedSymlinkCount; + std::vector VisitedSymlinks; + bool ListDirs; + bool RecurseListDirs; + +private: + Glob(const Glob&) = delete; + void operator=(const Glob&) = delete; +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/MD5.c b/MD5.c new file mode 100644 index 0000000000..fb18a5bba4 --- /dev/null +++ b/MD5.c @@ -0,0 +1,504 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(MD5.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "MD5.h.in" +#endif + +#include /* size_t */ +#include /* malloc, free */ +#include /* memcpy, strlen */ + +/* This MD5 implementation has been taken from a third party. Slight + modifications to the arrangement of the code have been made to put + it in a single source file instead of a separate header and + implementation file. */ + +#if defined(__clang__) && !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 + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s +{ + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) +{ + md5_word_t a = pms->abcd[0]; + md5_word_t b = pms->abcd[1]; + md5_word_t c = pms->abcd[2]; + md5_word_t d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t* X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t*)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t*)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t*)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t* xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) { + xbuf[i] = + (md5_word_t)(xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24)); + } + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +/* Round 1. */ +/* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + F(b, c, d) + X[k] + (Ti); \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + +/* Round 2. */ +/* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + G(b, c, d) + X[k] + (Ti); \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + +/* Round 3. */ +/* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + H(b, c, d) + X[k] + (Ti); \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + +/* Round 4. */ +/* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + I(b, c, d) + X[k] + (Ti); \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +/* Initialize the algorithm. */ +static void md5_init(md5_state_t* pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +/* Append a string to the message. */ +static void md5_append(md5_state_t* pms, const md5_byte_t* data, size_t nbytes) +{ + const md5_byte_t* p = data; + size_t left = nbytes; + size_t offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) { + return; + } + + /* Update the message length. */ + pms->count[1] += (md5_word_t)(nbytes >> 29); + pms->count[0] += nbits; + if (pms->count[0] < nbits) { + pms->count[1]++; + } + + /* Process an initial partial block. */ + if (offset) { + size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) { + return; + } + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) { + md5_process(pms, p); + } + + /* Process a final partial block. */ + if (left) { + memcpy(pms->buf, p, left); + } +} + +/* Finish the message and return the digest. */ +static void md5_finish(md5_state_t* pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) { + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + } + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) { + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); + } +} + +#if defined(__clang__) && !defined(__INTEL_COMPILER) +# pragma clang diagnostic pop +#endif + +/* Wrap up the MD5 state in our opaque structure. */ +struct kwsysMD5_s +{ + md5_state_t md5_state; +}; + +kwsysMD5* kwsysMD5_New(void) +{ + /* Allocate a process control structure. */ + kwsysMD5* md5 = (kwsysMD5*)malloc(sizeof(kwsysMD5)); + if (!md5) { + return 0; + } + return md5; +} + +void kwsysMD5_Delete(kwsysMD5* md5) +{ + /* Make sure we have an instance. */ + if (!md5) { + return; + } + + /* Free memory. */ + free(md5); +} + +void kwsysMD5_Initialize(kwsysMD5* md5) +{ + md5_init(&md5->md5_state); +} + +void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, int length) +{ + size_t dlen; + if (length < 0) { + dlen = strlen((char const*)data); + } else { + dlen = (size_t)length; + } + md5_append(&md5->md5_state, (md5_byte_t const*)data, dlen); +} + +void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]) +{ + md5_finish(&md5->md5_state, (md5_byte_t*)digest); +} + +void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]) +{ + unsigned char digest[16]; + kwsysMD5_Finalize(md5, digest); + kwsysMD5_DigestToHex(digest, buffer); +} + +void kwsysMD5_DigestToHex(unsigned char const digest[16], char buffer[32]) +{ + /* Map from 4-bit index to hexadecimal representation. */ + static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + /* Map each 4-bit block separately. */ + char* out = buffer; + int i; + for (i = 0; i < 16; ++i) { + *out++ = hex[digest[i] >> 4]; + *out++ = hex[digest[i] & 0xF]; + } +} diff --git a/MD5.h.in b/MD5.h.in new file mode 100644 index 0000000000..7646f1297a --- /dev/null +++ b/MD5.h.in @@ -0,0 +1,97 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_MD5_h +#define @KWSYS_NAMESPACE@_MD5_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysMD5 kwsys_ns(MD5) +# define kwsysMD5_s kwsys_ns(MD5_s) +# define kwsysMD5_New kwsys_ns(MD5_New) +# define kwsysMD5_Delete kwsys_ns(MD5_Delete) +# define kwsysMD5_Initialize kwsys_ns(MD5_Initialize) +# define kwsysMD5_Append kwsys_ns(MD5_Append) +# define kwsysMD5_Finalize kwsys_ns(MD5_Finalize) +# define kwsysMD5_FinalizeHex kwsys_ns(MD5_FinalizeHex) +# define kwsysMD5_DigestToHex kwsys_ns(MD5_DigestToHex) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * MD5 state data structure. + */ +typedef struct kwsysMD5_s kwsysMD5; + +/** + * Create a new MD5 instance. The returned instance is not initialized. + */ +kwsysEXPORT kwsysMD5* kwsysMD5_New(void); + +/** + * Delete an old MD5 instance. + */ +kwsysEXPORT void kwsysMD5_Delete(kwsysMD5* md5); + +/** + * Initialize a new MD5 digest. + */ +kwsysEXPORT void kwsysMD5_Initialize(kwsysMD5* md5); + +/** + * Append data to an MD5 digest. If the given length is negative, + * data will be read up to but not including a terminating null. + */ +kwsysEXPORT void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, + int length); + +/** + * Finalize a MD5 digest and get the 16-byte hash value. + */ +kwsysEXPORT void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]); + +/** + * Finalize a MD5 digest and get the 32-bit hexadecimal representation. + */ +kwsysEXPORT void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]); + +/** + * Convert a MD5 digest 16-byte value to a 32-byte hexadecimal representation. + */ +kwsysEXPORT void kwsysMD5_DigestToHex(unsigned char const digest[16], + char buffer[32]); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysMD5 +# undef kwsysMD5_s +# undef kwsysMD5_New +# undef kwsysMD5_Delete +# undef kwsysMD5_Initialize +# undef kwsysMD5_Append +# undef kwsysMD5_Finalize +# undef kwsysMD5_FinalizeHex +# undef kwsysMD5_DigestToHex +# endif +#endif + +#endif diff --git a/Process.h.in b/Process.h.in new file mode 100644 index 0000000000..9f2162b3dc --- /dev/null +++ b/Process.h.in @@ -0,0 +1,544 @@ +/* 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, const 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 diff --git a/ProcessUNIX.c b/ProcessUNIX.c new file mode 100644 index 0000000000..e1e7721b41 --- /dev/null +++ b/ProcessUNIX.c @@ -0,0 +1,2929 @@ +/* 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 */ +#include /* isspace */ +#include /* DIR, dirent */ +#include /* errno */ +#include /* fcntl */ +#include /* sigaction */ +#include /* ptrdiff_t */ +#include /* snprintf */ +#include /* malloc, free */ +#include /* strdup, strerror, memset */ +#include /* open mode */ +#include /* struct timeval */ +#include /* pid_t, fd_set */ +#include /* waitpid */ +#include /* gettimeofday */ +#include /* 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 +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, + const double* userTimeout, + kwsysProcessTime* timeoutTime); +static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, + const 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, const 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"; + } + 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"; + } + 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; + } + if (wd.Expired) { + /* A timeout has expired. */ + if (wd.User) { + /* The user timeout has expired. It has no time left. */ + return kwsysProcess_Pipe_Timeout; + } + + /* The process timeout has expired. Kill the children now. */ + kwsysProcess_Kill(cp); + cp->Killed = 0; + cp->TimeoutExpired = 1; + return kwsysProcess_Pipe_None; + } + /* 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); // NOLINT(readability-isolate-declaration) + + /* 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; + } + 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 = + // NOLINTNEXTLINE(google-readability-casting) + (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( + // NOLINTNEXTLINE(google-readability-casting) + 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); // NOLINT(readability-isolate-declaration) +#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; + sigset_t 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; + sigset_t old_mask; + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) { + return; + } + + for (i = 0; i < cp->NumberOfCommands; ++i) { + if (cp->ForkPIDs[i]) { + int result; + while (((result = waitpid(cp->ForkPIDs[i], &cp->CommandExitCodes[i], + WNOHANG)) < 0) && + (errno == EINTR)) { + } + if (result > 0) { + /* This child has termianted. */ + cp->ForkPIDs[i] = 0; + if (--cp->CommandsLeft == 0) { + /* All children have terminated. Close the signal pipe + write end so that no more notifications are sent to this + object. */ + kwsysProcessCleanupDescriptor(&cp->SignalPipe); + + /* TODO: Once the children have terminated, switch + WaitForData to use a non-blocking read to get the + rest of the data from the pipe. This is needed when + grandchildren keep the output pipes open. */ + } + } else if (result < 0 && cp->State != kwsysProcess_State_Error) { + /* Unexpected error. Report the first time this happens. */ + strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + cp->State = kwsysProcess_State_Error; + } + } + } + + /* Re-enable signals. */ + sigprocmask(SIG_SETMASK, &old_mask, 0); +} + +static int kwsysProcessSetupOutputPipeFile(int* p, const char* name) +{ + int fout; + if (!name) { + return 1; + } + + /* Close the existing descriptor. */ + kwsysProcessCleanupDescriptor(p); + + /* Open a file for the pipe to write. */ + if ((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { + return 0; + } + + /* Set close-on-exec flag on the pipe's end. */ + if (fcntl(fout, F_SETFD, FD_CLOEXEC) < 0) { + 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, + const 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, + const double* userTimeout, + kwsysProcessTimeNative* timeoutLength, + int zeroIsExpired) +{ + if (timeoutTime->tv_sec < 0) { + /* No timeout time has been requested. */ + return 0; + } + /* 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; + } + /* 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, "Subprocess aborted"); + break; +#endif +#ifdef SIGKILL + case SIGKILL: + KWSYSPE_CASE(Other, "Subprocess killed"); + break; +#endif +#ifdef SIGTERM + case SIGTERM: + KWSYSPE_CASE(Other, "Subprocess 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; + } + 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; + } + /* 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. */ + } + /* 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; + } + /* 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; + int 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; + int j; + int procStatus; + int old_errno = errno; +#if KWSYSPE_USE_SIGINFO + (void)info; + (void)ucontext; +#endif + + /* Signal all process objects that a child has terminated. */ + switch (signum) { + case SIGCHLD: + for (i = 0; i < kwsysProcesses.Count; ++i) { + /* Set the pipe in a signalled state. */ + char buf = 1; + kwsysProcess* cp = kwsysProcesses.Processes[i]; + kwsysProcess_ssize_t pipeStatus = + read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1); + (void)pipeStatus; + pipeStatus = write(cp->SignalPipe, &buf, 1); + (void)pipeStatus; + } + break; + case SIGINT: + case SIGTERM: + /* Signal child processes that are running in new process groups. */ + for (i = 0; i < kwsysProcesses.Count; ++i) { + kwsysProcess* cp = kwsysProcesses.Processes[i]; + /* Check Killed to avoid data race condition when killing. + Check State to avoid data race condition in kwsysProcessCleanup + when there is an error (it leaves a reaped PID). */ + if (cp->CreateProcessGroup && !cp->Killed && + cp->State != kwsysProcess_State_Error && cp->ForkPIDs) { + for (j = 0; j < cp->NumberOfCommands; ++j) { + /* Make sure the PID is still valid. */ + if (cp->ForkPIDs[j]) { + /* The user created a process group for this process. The group + ID + is the process ID for the original process in the group. */ + kill(-cp->ForkPIDs[j], SIGINT); + } + } + } + } + + /* Wait for all processes to terminate. */ + while (wait(&procStatus) >= 0 || errno != ECHILD) { + } + + /* Terminate the process, which is now in an inconsistent state + because we reaped all the PIDs that it may have been reaping + or may have reaped in the future. Reraise the signal so that + the proper exit code is returned. */ + { + /* Install default signal handler. */ + struct sigaction defSigAction; + sigset_t unblockSet; + memset(&defSigAction, 0, sizeof(defSigAction)); + defSigAction.sa_handler = SIG_DFL; + sigemptyset(&defSigAction.sa_mask); + while ((sigaction(signum, &defSigAction, 0) < 0) && (errno == EINTR)) { + } + /* Unmask the signal. */ + sigemptyset(&unblockSet); + sigaddset(&unblockSet, signum); + sigprocmask(SIG_UNBLOCK, &unblockSet, 0); + /* Raise the signal again. */ + raise(signum); + /* We shouldn't get here... but if we do... */ + _exit(1); + } + /* break omitted to silence unreachable code clang compiler warning. */ + } + +#if !KWSYSPE_USE_SIGINFO + /* Re-Install our handler. Repeat call until it is not interrupted. */ + { + struct sigaction newSigAction; + struct sigaction& oldSigAction; + memset(&newSigAction, 0, sizeof(struct sigaction)); + newSigChldAction.sa_handler = kwsysProcessesSignalHandler; + newSigChldAction.sa_flags = SA_NOCLDSTOP; + sigemptyset(&newSigAction.sa_mask); + switch (signum) { + case SIGCHLD: + oldSigAction = &kwsysProcessesOldSigChldAction; + break; + case SIGINT: + sigaddset(&newSigAction.sa_mask, SIGTERM); + oldSigAction = &kwsysProcessesOldSigIntAction; + break; + case SIGTERM: + sigaddset(&newSigAction.sa_mask, SIGINT); + oldSigAction = &kwsysProcessesOldSigTermAction; + break; + default: + return 0; + } + while ((sigaction(signum, &newSigAction, oldSigAction) < 0) && + (errno == EINTR)) + ; + } +#endif + + errno = old_errno; +} + +void kwsysProcess_ResetStartTime(kwsysProcess* cp) +{ + if (!cp) { + return; + } + /* Reset start time. */ + cp->StartTime = kwsysProcessTimeGetCurrent(); +} diff --git a/ProcessWin32.c b/ProcessWin32.c new file mode 100644 index 0000000000..12670762d9 --- /dev/null +++ b/ProcessWin32.c @@ -0,0 +1,2777 @@ +/* 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 API */ +#if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx +#endif +#include /* _unlink */ +#include /* sprintf */ +#include /* strlen, strdup */ + +#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 + +/* 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, const 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(); +} diff --git a/README.rst b/README.rst new file mode 100644 index 0000000000..fc6b5902ed --- /dev/null +++ b/README.rst @@ -0,0 +1,37 @@ +KWSys +***** + +Introduction +============ + +KWSys is the Kitware System Library. It provides platform-independent +APIs to many common system features that are implemented differently on +every platform. This library is intended to be shared among many +projects at the source level, so it has a configurable namespace. +Each project should configure KWSys to use a namespace unique to itself. +See comments in `CMakeLists.txt`_ for details. + +.. _`CMakeLists.txt`: CMakeLists.txt + +License +======= + +KWSys is distributed under the OSI-approved BSD 3-clause License. +See `Copyright.txt`_ for details. + +.. _`Copyright.txt`: Copyright.txt + +Reporting Bugs +============== + +KWSys has no independent issue tracker. After encountering an issue +(bug) please submit a patch using the instructions for `Contributing`_. +Otherwise please report the issue to the tracker for the project that +hosts the copy of KWSys in which the problem was found. + +Contributing +============ + +See `CONTRIBUTING.rst`_ for instructions to contribute. + +.. _`CONTRIBUTING.rst`: CONTRIBUTING.rst diff --git a/RegularExpression.cxx b/RegularExpression.cxx new file mode 100644 index 0000000000..fb4e38029a --- /dev/null +++ b/RegularExpression.cxx @@ -0,0 +1,1217 @@ +/* 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 +#include + +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(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(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 >= 65535L) { + // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big), + printf("RegularExpression::compile(): Expression too big.\n"); + return false; + } + + // Allocate space. + //#ifndef _WIN32 + delete[] this->program; + //#endif + this->program = new char[comp.regsize]; + this->progsize = static_cast(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(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(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((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(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((offset >> 8) & 0377); + *(scan + 2) = static_cast(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 diff --git a/RegularExpression.hxx.in b/RegularExpression.hxx.in new file mode 100644 index 0000000000..2709cde5f4 --- /dev/null +++ b/RegularExpression.hxx.in @@ -0,0 +1,567 @@ +/* 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 + +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; +}; + +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER < 1900 +# pragma warning(disable : 4351) /* new behavior */ +# endif +#endif + +/** + * \brief Creates an invalid match object + */ +inline RegularExpressionMatch::RegularExpressionMatch() + : startp{} + , endp{} + , searchstring{} +{ +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +/** + * \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(this->startp[0] - searchstring); +} + +/** + * \brief Returns the end index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end() const +{ + return static_cast(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(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(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(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 diff --git a/SharedForward.h.in b/SharedForward.h.in new file mode 100644 index 0000000000..091334b75d --- /dev/null +++ b/SharedForward.h.in @@ -0,0 +1,873 @@ +/* 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 + +/* 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 +# include +# include /* size_t */ +# include +# include +# include + +# if defined(_WIN32) && !defined(__CYGWIN__) +# include + +# include +# include +# define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */ +# else +# include +# include +# endif + +/* Configuration for this platform. */ + +/* The path separator for this platform. */ +# if defined(_WIN32) && !defined(__CYGWIN__) +# define KWSYS_SHARED_FORWARD_PATH_SEP ';' +# define KWSYS_SHARED_FORWARD_PATH_SLASH '\\' +# else +# define KWSYS_SHARED_FORWARD_PATH_SEP ':' +# define KWSYS_SHARED_FORWARD_PATH_SLASH '/' +# endif +static const char kwsys_shared_forward_path_sep[2] = { + KWSYS_SHARED_FORWARD_PATH_SEP, 0 +}; +static const char kwsys_shared_forward_path_slash[2] = { + KWSYS_SHARED_FORWARD_PATH_SLASH, 0 +}; + +/* The maximum length of a file name. */ +# if defined(PATH_MAX) +# define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX +# elif defined(MAXPATHLEN) +# define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN +# else +# define KWSYS_SHARED_FORWARD_MAXPATH 16384 +# endif + +/* Select the environment variable holding the shared library runtime + search path for this platform and build configuration. Also select + ldd command equivalent. */ + +/* Linux */ +# if defined(__linux) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" + +/* FreeBSD */ +# elif defined(__FreeBSD__) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" + +/* OpenBSD */ +# elif defined(__OpenBSD__) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" + +/* 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 +# if defined(_ILP32) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# elif defined(_LP64) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64" +# endif + +/* HP-UX */ +# elif defined(__hpux) +# define KWSYS_SHARED_FORWARD_LDD "chatr" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# if defined(__LP64__) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# else +# define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH" +# endif + +/* SGI MIPS */ +# elif defined(__sgi) && defined(_MIPS_SIM) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# if _MIPS_SIM == _ABIO32 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# elif _MIPS_SIM == _ABIN32 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH" +# elif _MIPS_SIM == _ABI64 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH" +# endif + +/* Cygwin */ +# elif defined(__CYGWIN__) +# define KWSYS_SHARED_FORWARD_LDD \ + "cygcheck" /* TODO: cygwin 1.7 has ldd \ + */ +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "PATH" + +/* Windows */ +# elif defined(_WIN32) +# define KWSYS_SHARED_FORWARD_LDPATH "PATH" + +/* Guess on this unknown system. */ +# else +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# endif + +# ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV +typedef struct kwsys_sf_arg_info_s +{ + const char* arg; + int size; + int quote; +} kwsys_sf_arg_info; + +static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in) +{ + /* Initialize information. */ + kwsys_sf_arg_info info; + + /* String iterator. */ + const char* c; + + /* Keep track of how many backslashes have been encountered in a row. */ + int windows_backslashes = 0; + + /* Start with the length of the original argument, plus one for + either a terminating null or a separating space. */ + info.arg = in; + info.size = (int)strlen(in) + 1; + info.quote = 0; + + /* Scan the string for characters that require escaping or quoting. */ + for (c = in; *c; ++c) { + /* Check whether this character needs quotes. */ + if (strchr(" \t?'#&<>|^", *c)) { + info.quote = 1; + } + + /* On Windows only backslashes and double-quotes need escaping. */ + if (*c == '\\') { + /* Found a backslash. It may need to be escaped later. */ + ++windows_backslashes; + } else if (*c == '"') { + /* Found a double-quote. We need to escape it and all + immediately preceding backslashes. */ + info.size += windows_backslashes + 1; + windows_backslashes = 0; + } else { + /* Found another character. This eliminates the possibility + that any immediately preceding backslashes will be + escaped. */ + windows_backslashes = 0; + } + } + + /* Check whether the argument needs surrounding quotes. */ + if (info.quote) { + /* Surrounding quotes are needed. Allocate space for them. */ + info.size += 2; + + /* We must escape all ending backslashes when quoting on windows. */ + info.size += windows_backslashes; + } + + return info; +} + +static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out) +{ + /* String iterator. */ + const char* c; + + /* Keep track of how many backslashes have been encountered in a row. */ + int windows_backslashes = 0; + + /* Whether the argument must be quoted. */ + if (info.quote) { + /* Add the opening quote for this argument. */ + *out++ = '"'; + } + + /* Scan the string for characters that require escaping or quoting. */ + for (c = info.arg; *c; ++c) { + /* On Windows only backslashes and double-quotes need escaping. */ + if (*c == '\\') { + /* Found a backslash. It may need to be escaped later. */ + ++windows_backslashes; + } else if (*c == '"') { + /* Found a double-quote. Escape all immediately preceding + backslashes. */ + while (windows_backslashes > 0) { + --windows_backslashes; + *out++ = '\\'; + } + + /* Add the backslash to escape the double-quote. */ + *out++ = '\\'; + } else { + /* We encountered a normal character. This eliminates any + escaping needed for preceding backslashes. */ + windows_backslashes = 0; + } + + /* Store this character. */ + *out++ = *c; + } + + if (info.quote) { + /* Add enough backslashes to escape any trailing ones. */ + while (windows_backslashes > 0) { + --windows_backslashes; + *out++ = '\\'; + } + + /* Add the closing quote for this argument. */ + *out++ = '"'; + } + + /* Store a terminating null without incrementing. */ + *out = 0; + + return out; +} +# endif + +/* Function to convert a logical or relative path to a physical full path. */ +static int kwsys_shared_forward_realpath(const char* in_path, char* out_path) +{ +# if defined(_WIN32) && !defined(__CYGWIN__) + /* Implementation for Windows. */ + DWORD n = + GetFullPathNameA(in_path, KWSYS_SHARED_FORWARD_MAXPATH, out_path, 0); + return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH; +# else + /* Implementation for UNIX. */ + return realpath(in_path, out_path) != 0; +# endif +} + +static int kwsys_shared_forward_samepath(const char* file1, const char* file2) +{ +# if defined(_WIN32) + int result = 0; + HANDLE h1 = CreateFileA(file1, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + HANDLE h2 = CreateFileA(file2, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE) { + BY_HANDLE_FILE_INFORMATION fi1; + BY_HANDLE_FILE_INFORMATION fi2; + GetFileInformationByHandle(h1, &fi1); + GetFileInformationByHandle(h2, &fi2); + result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber && + fi1.nFileIndexHigh == fi2.nFileIndexHigh && + fi1.nFileIndexLow == fi2.nFileIndexLow); + } + CloseHandle(h1); + CloseHandle(h2); + return result; +# else + struct stat fs1, fs2; + return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 && + memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 && + memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 && + fs2.st_size == fs1.st_size); +# endif +} + +/* Function to report a system error message. */ +static void kwsys_shared_forward_strerror(char* message) +{ +# if defined(_WIN32) && !defined(__CYGWIN__) + /* Implementation for Windows. */ + DWORD original = GetLastError(); + DWORD length = + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, original, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + message, KWSYS_SHARED_FORWARD_MAXPATH, 0); + if (length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) { + /* FormatMessage failed. Use a default message. */ + _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH, + "Error 0x%X (FormatMessage failed with error 0x%X)", original, + GetLastError()); + } +# else + /* Implementation for UNIX. */ + strcpy(message, strerror(errno)); +# endif +} + +/* Functions to execute a child process. */ +static void kwsys_shared_forward_execvp(const char* cmd, + char const* const* argv) +{ +# ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV + /* Count the number of arguments. */ + int argc = 0; + { + char const* const* argvc; + for (argvc = argv; *argvc; ++argvc, ++argc) { + } + } + + /* Create the escaped arguments. */ + { + char** nargv = (char**)malloc((argc + 1) * sizeof(char*)); + int i; + for (i = 0; i < argc; ++i) { + kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]); + nargv[i] = (char*)malloc(info.size); + kwsys_sf_get_arg(info, nargv[i]); + } + nargv[argc] = 0; + + /* Replace the command line to be used. */ + argv = (char const* const*)nargv; + } +# endif + +/* Invoke the child process. */ +# if defined(_MSC_VER) + _execvp(cmd, argv); +# elif defined(__MINGW32__) && !defined(__MINGW64__) + execvp(cmd, argv); +# else + execvp(cmd, (char* const*)argv); +# endif +} + +/* Function to get the directory containing the given file or directory. */ +static void kwsys_shared_forward_dirname(const char* begin, char* result) +{ + /* Find the location of the last slash. */ + int last_slash_index = -1; + const char* end = begin + strlen(begin); + for (; begin <= end && last_slash_index < 0; --end) { + if (*end == '/' || *end == '\\') { + last_slash_index = (int)(end - begin); + } + } + + /* Handle each case of the index of the last slash. */ + if (last_slash_index < 0) { + /* No slashes. */ + strcpy(result, "."); + } else if (last_slash_index == 0) { + /* Only one leading slash. */ + strcpy(result, kwsys_shared_forward_path_slash); + } +# if defined(_WIN32) + else if (last_slash_index == 2 && begin[1] == ':') { + /* Only one leading drive letter and slash. */ + strncpy(result, begin, (size_t)last_slash_index); + result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH; + result[last_slash_index + 1] = 0; + } +# endif + else { + /* A non-leading slash. */ + strncpy(result, begin, (size_t)last_slash_index); + result[last_slash_index] = 0; + } +} + +/* Function to check if a file exists and is executable. */ +static int kwsys_shared_forward_is_executable(const char* f) +{ +# if defined(_MSC_VER) +# define KWSYS_SHARED_FORWARD_ACCESS _access +# else +# define KWSYS_SHARED_FORWARD_ACCESS access +# endif +# if defined(X_OK) +# define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK +# else +# define KWSYS_SHARED_FORWARD_ACCESS_OK 04 +# endif + if (KWSYS_SHARED_FORWARD_ACCESS(f, KWSYS_SHARED_FORWARD_ACCESS_OK) == 0) { + return 1; + } else { + return 0; + } +} + +/* Function to locate the executable currently running. */ +static int kwsys_shared_forward_self_path(const char* argv0, char* result) +{ + /* Check whether argv0 has a slash. */ + int has_slash = 0; + const char* p = argv0; + for (; *p && !has_slash; ++p) { + if (*p == '/' || *p == '\\') { + has_slash = 1; + } + } + + if (has_slash) { + /* There is a slash. Use the dirname of the given location. */ + kwsys_shared_forward_dirname(argv0, result); + return 1; + } else { + /* There is no slash. Search the PATH for the executable. */ + const char* path = getenv("PATH"); + const char* begin = path; + const char* end = begin + (begin ? strlen(begin) : 0); + const char* first = begin; + while (first != end) { + /* Store the end of this path entry. */ + const char* last; + + /* Skip all path separators. */ + for (; *first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first) + ; + + /* Find the next separator. */ + for (last = first; *last && *last != KWSYS_SHARED_FORWARD_PATH_SEP; + ++last) + ; + + /* If we got a non-empty directory, look for the executable there. */ + if (first < last) { + /* Determine the length without trailing slash. */ + size_t length = (size_t)(last - first); + if (*(last - 1) == '/' || *(last - 1) == '\\') { + --length; + } + + /* Construct the name of the executable in this location. */ + strncpy(result, first, length); + result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH; + strcpy(result + (length) + 1, argv0); + + /* Check if it exists and is executable. */ + if (kwsys_shared_forward_is_executable(result)) { + /* Found it. */ + result[length] = 0; + return 1; + } + } + + /* Move to the next directory in the path. */ + first = last; + } + } + + /* We could not find the executable. */ + return 0; +} + +/* Function to convert a specified path to a full path. If it is not + already full, it is taken relative to the self path. */ +static int kwsys_shared_forward_fullpath(const char* self_path, + const char* in_path, char* result, + const char* desc) +{ + /* Check the specified path type. */ + if (in_path[0] == '/') { + /* Already a full path. */ + strcpy(result, in_path); + } +# if defined(_WIN32) + else if (in_path[0] && in_path[1] == ':') { + /* Already a full path. */ + strcpy(result, in_path); + } +# endif + else { + /* Relative to self path. */ + char temp_path[KWSYS_SHARED_FORWARD_MAXPATH]; + strcpy(temp_path, self_path); + strcat(temp_path, kwsys_shared_forward_path_slash); + strcat(temp_path, in_path); + if (!kwsys_shared_forward_realpath(temp_path, result)) { + if (desc) { + char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; + kwsys_shared_forward_strerror(msgbuf); + fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", desc, + temp_path, msgbuf); + } + return 0; + } + } + return 1; +} + +/* Function to compute the library search path and executable name + based on the self path. */ +static int kwsys_shared_forward_get_settings(const char* self_path, + char* ldpath, char* exe) +{ + /* Possible search paths. */ + static const char* search_path_build[] = { KWSYS_SHARED_FORWARD_PATH_BUILD, + 0 }; + static const char* search_path_install[] = { + KWSYS_SHARED_FORWARD_PATH_INSTALL, 0 + }; + + /* Chosen paths. */ + const char** search_path; + const char* exe_path; + +/* Get the real name of the build and self paths. */ +# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) + char build_path[] = + KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME; + char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH]; +# else + char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD; + const char* self_path_logical = self_path; +# endif + char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; + char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; + if (!kwsys_shared_forward_realpath(self_path, self_path_real)) { + char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; + kwsys_shared_forward_strerror(msgbuf); + fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n", + self_path, msgbuf); + return 0; + } + + /* Check whether we are running in the build tree or an install tree. */ + if (kwsys_shared_forward_realpath(build_path, build_path_real) && + kwsys_shared_forward_samepath(self_path_real, build_path_real)) { + /* Running in build tree. Use the build path and exe. */ + search_path = search_path_build; +# if defined(_WIN32) + exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe"; +# else + exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD; +# endif + +# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) + /* Remove the configuration directory from self_path. */ + kwsys_shared_forward_dirname(self_path, self_path_logical); +# endif + } else { + /* Running in install tree. Use the install path and exe. */ + search_path = search_path_install; +# if defined(_WIN32) + exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe"; +# else + exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL; +# endif + +# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) + /* Use the original self path directory. */ + strcpy(self_path_logical, self_path); +# endif + } + + /* Construct the runtime search path. */ + { + const char** dir; + for (dir = search_path; *dir; ++dir) { + /* Add separator between path components. */ + if (dir != search_path) { + strcat(ldpath, kwsys_shared_forward_path_sep); + } + + /* Add this path component. */ + if (!kwsys_shared_forward_fullpath(self_path_logical, *dir, + ldpath + strlen(ldpath), + "runtime path entry")) { + return 0; + } + } + } + + /* Construct the executable location. */ + if (!kwsys_shared_forward_fullpath(self_path_logical, exe_path, exe, + "executable file")) { + return 0; + } + return 1; +} + +/* Function to print why execution of a command line failed. */ +static void kwsys_shared_forward_print_failure(char const* const* argv) +{ + char msg[KWSYS_SHARED_FORWARD_MAXPATH]; + char const* const* arg = argv; + kwsys_shared_forward_strerror(msg); + fprintf(stderr, "Error running"); + for (; *arg; ++arg) { + fprintf(stderr, " \"%s\"", *arg); + } + fprintf(stderr, ": %s\n", msg); +} + +/* Static storage space to store the updated environment variable. */ +static char kwsys_shared_forward_ldpath[65535] = + KWSYS_SHARED_FORWARD_LDPATH "="; + +/* Main driver function to be called from main. */ +static int @KWSYS_NAMESPACE@_shared_forward_to_real(int argc, char** argv_in) +{ + char const** argv = (char const**)argv_in; + /* Get the directory containing this executable. */ + char self_path[KWSYS_SHARED_FORWARD_MAXPATH]; + if (kwsys_shared_forward_self_path(argv[0], self_path)) { + /* Found this executable. Use it to get the library directory. */ + char exe[KWSYS_SHARED_FORWARD_MAXPATH]; + if (kwsys_shared_forward_get_settings(self_path, + kwsys_shared_forward_ldpath, exe)) { + /* Append the old runtime search path. */ + const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH); + if (old_ldpath) { + strcat(kwsys_shared_forward_ldpath, kwsys_shared_forward_path_sep); + strcat(kwsys_shared_forward_ldpath, old_ldpath); + } + + /* Store the environment variable. */ + putenv(kwsys_shared_forward_ldpath); + +# if defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND) + /* Look for the command line replacement option. */ + if (argc > 1 && + strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0) { + if (argc > 2) { + /* Use the command line given. */ + strcpy(exe, argv[2]); + argv += 2; + argc -= 2; + } else { + /* The option was not given an executable. */ + fprintf(stderr, + "Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND + " must be followed by a command line.\n"); + return 1; + } + } +# endif + +# if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT) + /* Look for the print command line option. */ + if (argc > 1 && + strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0) { + fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath); + fprintf(stdout, "%s\n", exe); + return 0; + } +# endif + +# if defined(KWSYS_SHARED_FORWARD_OPTION_LDD) + /* Look for the ldd command line option. */ + if (argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0) { +# if defined(KWSYS_SHARED_FORWARD_LDD) + /* Use the named ldd-like executable and arguments. */ + char const* ldd_argv[] = { KWSYS_SHARED_FORWARD_LDD, 0, 0 }; + ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe; + kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv); + + /* Report why execution failed. */ + kwsys_shared_forward_print_failure(ldd_argv); + return 1; +# else + /* We have no ldd-like executable available on this platform. */ + fprintf(stderr, "No ldd-like tool is known to this executable.\n"); + return 1; +# endif + } +# endif + + /* Replace this process with the real executable. */ + argv[0] = exe; + kwsys_shared_forward_execvp(argv[0], argv); + + /* Report why execution failed. */ + kwsys_shared_forward_print_failure(argv); + } else { + /* Could not convert self path to the library directory. */ + } + } else { + /* Could not find this executable. */ + fprintf(stderr, "Error locating executable \"%s\".\n", argv[0]); + } + + /* Avoid unused argument warning. */ + (void)argc; + + /* Exit with failure. */ + return 1; +} + +/* Restore warning stack. */ +# if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wcast-qual") +# pragma clang diagnostic pop +# endif +# endif + +#else +# error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once." +#endif diff --git a/String.c b/String.c new file mode 100644 index 0000000000..daf7ad1a0f --- /dev/null +++ b/String.c @@ -0,0 +1,100 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef KWSYS_STRING_C +/* +All code in this source file is conditionally compiled to work-around +template definition auto-search on VMS. Other source files in this +directory that use the stl string cause the compiler to load this +source to try to get the definition of the string template. This +condition blocks the compiler from seeing the symbols defined here. +*/ +# include "kwsysPrivate.h" +# include KWSYS_HEADER(String.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +# if 0 +# include "String.h.in" +# endif + +/* Select an implementation for strcasecmp. */ +# if defined(_MSC_VER) +# define KWSYS_STRING_USE_STRICMP +# include +# elif defined(__GNUC__) +# define KWSYS_STRING_USE_STRCASECMP +# include +# else +/* Table to convert upper case letters to lower case and leave all + other characters alone. */ +static char kwsysString_strcasecmp_tolower[] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', + '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', + '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', + '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043', + '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054', + '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065', + '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076', + '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', + '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', + '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142', + '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', + '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', + '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175', + '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', + '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', + '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', + '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', + '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', + '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', + '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', + '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', + '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', + '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', + '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', + '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', + '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', + '\374', '\375', '\376', '\377' +}; +# endif + +/*--------------------------------------------------------------------------*/ +int kwsysString_strcasecmp(const char* lhs, const char* rhs) +{ +# if defined(KWSYS_STRING_USE_STRICMP) + return _stricmp(lhs, rhs); +# elif defined(KWSYS_STRING_USE_STRCASECMP) + return strcasecmp(lhs, rhs); +# else + const char* const lower = kwsysString_strcasecmp_tolower; + unsigned char const* us1 = (unsigned char const*)lhs; + unsigned char const* us2 = (unsigned char const*)rhs; + int result; + while ((result = lower[*us1] - lower[*us2++], result == 0) && *us1++) { + } + return result; +# endif +} + +/*--------------------------------------------------------------------------*/ +int kwsysString_strncasecmp(const char* lhs, const char* rhs, size_t n) +{ +# if defined(KWSYS_STRING_USE_STRICMP) + return _strnicmp(lhs, rhs, n); +# elif defined(KWSYS_STRING_USE_STRCASECMP) + return strncasecmp(lhs, rhs, n); +# else + const char* const lower = kwsysString_strcasecmp_tolower; + unsigned char const* us1 = (unsigned char const*)lhs; + unsigned char const* us2 = (unsigned char const*)rhs; + int result = 0; + while (n && (result = lower[*us1] - lower[*us2++], result == 0) && *us1++) { + --n; + } + return result; +# endif +} + +#endif /* KWSYS_STRING_C */ diff --git a/String.h.in b/String.h.in new file mode 100644 index 0000000000..7c9348af13 --- /dev/null +++ b/String.h.in @@ -0,0 +1,57 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_String_h +#define @KWSYS_NAMESPACE@_String_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include /* size_t */ + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysString_strcasecmp kwsys_ns(String_strcasecmp) +# define kwsysString_strncasecmp kwsys_ns(String_strncasecmp) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Compare two strings ignoring the case of the characters. The + * integer returned is negative, zero, or positive if the first string + * is found to be less than, equal to, or greater than the second + * string, respectively. + */ +kwsysEXPORT int kwsysString_strcasecmp(const char* lhs, const char* rhs); + +/** + * Identical to String_strcasecmp except that only the first n + * characters are considered. + */ +kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs, + size_t n); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysString_strcasecmp +# undef kwsysString_strncasecmp +# endif +#endif + +#endif diff --git a/String.hxx.in b/String.hxx.in new file mode 100644 index 0000000000..c36f4ce4a9 --- /dev/null +++ b/String.hxx.in @@ -0,0 +1,57 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_String_hxx +#define @KWSYS_NAMESPACE@_String_hxx + +#include + +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 + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/System.c b/System.c new file mode 100644 index 0000000000..dbfd2fd169 --- /dev/null +++ b/System.c @@ -0,0 +1,236 @@ +/* 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 /* isspace */ +#include /* ptrdiff_t */ +#include /* malloc, free */ +#include /* memcpy */ + +#include + +#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T +typedef ptrdiff_t kwsysSystem_ptrdiff_t; +#else +typedef int kwsysSystem_ptrdiff_t; +#endif + +static int kwsysSystem__AppendByte(const char* local, char** begin, char** end, + int* size, char c) +{ + /* Allocate space for the character. */ + if ((*end - *begin) >= *size) { + kwsysSystem_ptrdiff_t length = *end - *begin; + char* newBuffer = (char*)malloc((size_t)(*size * 2)); + if (!newBuffer) { + return 0; + } + memcpy(newBuffer, *begin, (size_t)(length) * sizeof(char)); + if (*begin != local) { + free(*begin); + } + *begin = newBuffer; + *end = *begin + length; + *size *= 2; + } + + /* Store the character. */ + *(*end)++ = c; + return 1; +} + +static int kwsysSystem__AppendArgument(char** local, char*** begin, + char*** end, int* size, char* arg_local, + char** arg_begin, char** arg_end, + int* arg_size) +{ + /* Append a null-terminator to the argument string. */ + if (!kwsysSystem__AppendByte(arg_local, arg_begin, arg_end, arg_size, + '\0')) { + return 0; + } + + /* Allocate space for the argument pointer. */ + if ((*end - *begin) >= *size) { + kwsysSystem_ptrdiff_t length = *end - *begin; + char** newPointers = (char**)malloc((size_t)(*size) * 2 * sizeof(char*)); + if (!newPointers) { + return 0; + } + memcpy(newPointers, *begin, (size_t)(length) * sizeof(char*)); + if (*begin != local) { + free(*begin); + } + *begin = newPointers; + *end = *begin + length; + *size *= 2; + } + + /* Allocate space for the argument string. */ + **end = (char*)malloc((size_t)(*arg_end - *arg_begin)); + if (!**end) { + return 0; + } + + /* Store the argument in the command array. */ + memcpy(**end, *arg_begin, (size_t)(*arg_end - *arg_begin)); + ++(*end); + + /* Reset the argument to be empty. */ + *arg_end = *arg_begin; + + return 1; +} + +#define KWSYSPE_LOCAL_BYTE_COUNT 1024 +#define KWSYSPE_LOCAL_ARGS_COUNT 32 +static char** kwsysSystem__ParseUnixCommand(const char* command, int flags) +{ + /* Create a buffer for argument pointers during parsing. */ + char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT]; + int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT; + char** pointer_begin = local_pointers; + char** pointer_end = pointer_begin; + + /* Create a buffer for argument strings during parsing. */ + char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT]; + int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT; + char* buffer_begin = local_buffer; + char* buffer_end = buffer_begin; + + /* Parse the command string. Try to behave like a UNIX shell. */ + char** newCommand = 0; + const char* c = command; + int in_argument = 0; + int in_escape = 0; + int in_single = 0; + int in_double = 0; + int failed = 0; + for (; *c; ++c) { + if (in_escape) { + /* This character is escaped so do no special handling. */ + if (!in_argument) { + in_argument = 1; + } + if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end, + &buffer_size, *c)) { + failed = 1; + break; + } + in_escape = 0; + } else if (*c == '\\') { + /* The next character should be escaped. */ + in_escape = 1; + } else if (*c == '\'' && !in_double) { + /* Enter or exit single-quote state. */ + if (in_single) { + in_single = 0; + } else { + in_single = 1; + if (!in_argument) { + in_argument = 1; + } + } + } else if (*c == '"' && !in_single) { + /* Enter or exit double-quote state. */ + if (in_double) { + in_double = 0; + } else { + in_double = 1; + if (!in_argument) { + in_argument = 1; + } + } + } else if (isspace((unsigned char)*c)) { + if (in_argument) { + if (in_single || in_double) { + /* This space belongs to a quoted argument. */ + if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, + &buffer_end, &buffer_size, *c)) { + failed = 1; + break; + } + } else { + /* This argument has been terminated by whitespace. */ + if (!kwsysSystem__AppendArgument( + local_pointers, &pointer_begin, &pointer_end, &pointers_size, + local_buffer, &buffer_begin, &buffer_end, &buffer_size)) { + failed = 1; + break; + } + in_argument = 0; + } + } + } else { + /* This character belong to an argument. */ + if (!in_argument) { + in_argument = 1; + } + if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end, + &buffer_size, *c)) { + failed = 1; + break; + } + } + } + + /* Finish the last argument. */ + if (in_argument) { + if (!kwsysSystem__AppendArgument( + local_pointers, &pointer_begin, &pointer_end, &pointers_size, + local_buffer, &buffer_begin, &buffer_end, &buffer_size)) { + failed = 1; + } + } + + /* If we still have memory allocate space for the new command + buffer. */ + if (!failed) { + kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin; + newCommand = (char**)malloc((size_t)(n + 1) * sizeof(char*)); + } + + if (newCommand) { + /* Copy the arguments into the new command buffer. */ + kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin; + memcpy(newCommand, pointer_begin, sizeof(char*) * (size_t)(n)); + newCommand[n] = 0; + } else { + /* Free arguments already allocated. */ + while (pointer_end != pointer_begin) { + free(*(--pointer_end)); + } + } + + /* Free temporary buffers. */ + if (pointer_begin != local_pointers) { + free(pointer_begin); + } + if (buffer_begin != local_buffer) { + free(buffer_begin); + } + + /* The flags argument is currently unused. */ + (void)flags; + + /* Return the final command buffer. */ + return newCommand; +} + +char** kwsysSystem_Parse_CommandForUnix(const char* command, int flags) +{ + /* Validate the flags. */ + if (flags != 0) { + return 0; + } + + /* Forward to our internal implementation. */ + return kwsysSystem__ParseUnixCommand(command, flags); +} diff --git a/System.h.in b/System.h.in new file mode 100644 index 0000000000..a9d4f5e690 --- /dev/null +++ b/System.h.in @@ -0,0 +1,60 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_System_h +#define @KWSYS_NAMESPACE@_System_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysSystem_Parse_CommandForUnix \ + kwsys_ns(System_Parse_CommandForUnix) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Parse a unix-style command line string into separate arguments. + * + * On success, returns a pointer to an array of pointers to individual + * argument strings. Each string is null-terminated and the last + * entry in the array is a NULL pointer (just like argv). It is the + * caller's responsibility to free() the strings and the array of + * pointers to them. + * + * On failure, returns NULL. Failure occurs only on invalid flags or + * when memory cannot be allocated; never due to content of the input + * string. Missing close-quotes are treated as if the necessary + * closing quote appears. + * + * By default single- and double-quoted arguments are supported, and + * any character may be escaped by a backslash. The flags argument is + * reserved for future use, and must be zero (or the call will fail). + */ +kwsysEXPORT char** kwsysSystem_Parse_CommandForUnix(const char* command, + int flags); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysSystem_Parse_CommandForUnix +# endif +#endif + +#endif diff --git a/SystemInformation.cxx b/SystemInformation.cxx new file mode 100644 index 0000000000..9c34a565af --- /dev/null +++ b/SystemInformation.cxx @@ -0,0 +1,5471 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#if defined(_WIN32) +# define NOMINMAX // use our min,max +# if !defined(_WIN32_WINNT) && defined(_MSC_VER) && _MSC_VER >= 1800 +# define _WIN32_WINNT 0x0600 // vista +# endif +# if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300) +# define _WIN32_WINNT 0x0501 +# endif +# include // WSADATA, include before sys/types.h +#endif + +#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif + +// TODO: +// We need an alternative implementation for many functions in this file +// when USE_ASM_INSTRUCTIONS gets defined as 0. +// +// Consider using these on Win32/Win64 for some of them: +// +// IsProcessorFeaturePresent +// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx +// +// GetProcessMemoryInfo +// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx + +#include "kwsysPrivate.h" +#include KWSYS_HEADER(SystemInformation.hxx) +#include KWSYS_HEADER(Process.h) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Process.h.in" +# include "SystemInformation.hxx.in" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +# include +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# endif +# include +# if defined(KWSYS_SYS_HAS_PSAPI) +# include +# endif +# if !defined(siginfo_t) +typedef int siginfo_t; +# endif +#else +# include + +# include // extern int errno; +# include +# include +# include // getrlimit +# include +# include // int uname(struct utsname *buf); +# include +#endif + +#if defined(__CYGWIN__) && !defined(_WIN32) +# include +# undef _WIN32 +#endif + +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) +# include +# include +# include +# include +# include +# if defined(KWSYS_SYS_HAS_IFADDRS_H) +# include +# include +# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN +# endif +#endif + +#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H) +# include +#endif + +#ifdef __APPLE__ +# include +# include +# include +# include +# include +# include +# include +# include +# if defined(KWSYS_SYS_HAS_IFADDRS_H) +# include +# include +# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN +# endif +# if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050) +# undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE +# endif +#endif + +#if defined(__linux) || defined(__sun) || defined(_SCO_DS) || \ + defined(__GLIBC__) || defined(__GNU__) +# include +# include +# include +# if defined(KWSYS_SYS_HAS_IFADDRS_H) +# include +# include +# if defined(__LSB_VERSION__) +/* LSB has no getifaddrs */ +# elif defined(__ANDROID_API__) && __ANDROID_API__ < 24 +/* Android has no getifaddrs prior to API 24. */ +# else +# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN +# endif +# endif +# if defined(KWSYS_CXX_HAS_RLIMIT64) +using ResourceLimitType = struct rlimit64; +# define GetResourceLimit getrlimit64 +# else +typedef struct rlimit ResourceLimitType; +# define GetResourceLimit getrlimit +# endif +#elif defined(__hpux) +# include +# include +# if defined(KWSYS_SYS_HAS_MPCTL_H) +# include +# endif +#endif + +#ifdef __HAIKU__ +# include +#endif + +#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) +# include +# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) +# include +# endif +# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) +# include +# endif +#else +# undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE +# undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP +#endif + +#include // int isdigit(int c); +#include +#include +#include +#include + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && \ + !defined(__clang__) +# define USE_ASM_INSTRUCTIONS 1 +#else +# define USE_ASM_INSTRUCTIONS 0 +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__) && \ + !defined(_M_ARM64) +# include +# define USE_CPUID_INTRINSICS 1 +#else +# define USE_CPUID_INTRINSICS 0 +#endif + +#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS +# define USE_CPUID 1 +#else +# define USE_CPUID 0 +#endif + +#if USE_CPUID + +# define CPUID_AWARE_COMPILER + +/** + * call CPUID instruction + * + * Will return false if the instruction failed. + */ +static bool call_cpuid(int select, int result[4]) +{ +# if USE_CPUID_INTRINSICS + __cpuid(result, select); + return true; +# else + int tmp[4]; +# if defined(_MSC_VER) + // Use SEH to determine CPUID presence + __try { + _asm { +# ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser does not know about <>, and so does not expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +# endif + ; <> + mov eax, select +# ifdef CPUID_AWARE_COMPILER + cpuid +# else + _asm _emit 0x0f + _asm _emit 0xa2 +# endif + mov tmp[0 * TYPE int], eax + mov tmp[1 * TYPE int], ebx + mov tmp[2 * TYPE int], ecx + mov tmp[3 * TYPE int], edx + +# ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +# endif + } + } __except (1) { + return false; + } + + memcpy(result, tmp, sizeof(tmp)); +# endif + + // The cpuid instruction succeeded. + return true; +# endif +} +#endif + +namespace KWSYS_NAMESPACE { +template +T min(T a, T b) +{ + return a < b ? a : b; +} + +extern "C" { +using SigAction = void (*)(int, siginfo_t*, void*); +} + +// Define SystemInformationImplementation class +using DELAY_FUNC = void (*)(unsigned int); + +class SystemInformationImplementation +{ +public: + SystemInformationImplementation(); + ~SystemInformationImplementation() = default; + + const char* GetVendorString() const; + const char* GetVendorID(); + std::string GetTypeID() const; + std::string GetFamilyID() const; + std::string GetModelID() const; + std::string GetModelName() const; + std::string GetSteppingCode() const; + const char* GetExtendedProcessorName() const; + const char* GetProcessorSerialNumber() const; + int GetProcessorCacheSize() const; + unsigned int GetLogicalProcessorsPerPhysical() const; + float GetProcessorClockFrequency() const; + int GetProcessorAPICID() const; + int GetProcessorCacheXSize(long int) const; + bool DoesCPUSupportFeature(long int) const; + + const char* GetOSName(); + const char* GetHostname(); + int GetFullyQualifiedDomainName(std::string& fqdn); + const char* GetOSRelease(); + const char* GetOSVersion(); + const char* GetOSPlatform(); + + bool Is64Bits() const; + + unsigned int GetNumberOfLogicalCPU() const; // per physical cpu + unsigned int GetNumberOfPhysicalCPU() const; + + bool DoesCPUSupportCPUID(); + + // Retrieve memory information in MiB. + size_t GetTotalVirtualMemory() const; + size_t GetAvailableVirtualMemory() const; + size_t GetTotalPhysicalMemory() const; + size_t GetAvailablePhysicalMemory() const; + + long long GetProcessId(); + + // Retrieve memory information in KiB. + long long GetHostMemoryTotal(); + long long GetHostMemoryAvailable(const char* hostLimitEnvVarName); + long long GetHostMemoryUsed(); + + long long GetProcMemoryAvailable(const char* hostLimitEnvVarName, + const char* procLimitEnvVarName); + long long GetProcMemoryUsed(); + + double GetLoadAverage(); + + // enable/disable stack trace signal handler. + static void SetStackTraceOnError(int enable); + + // get current stack + static std::string GetProgramStack(int firstFrame, int wholePath); + + /** Run the different checks */ + void RunCPUCheck(); + void RunOSCheck(); + void RunMemoryCheck(); + +public: + using ID = struct tagID + + { + + int Type; + + int Family; + + int Model; + + int Revision; + + int ExtendedFamily; + + int ExtendedModel; + + std::string ProcessorName; + + std::string Vendor; + + std::string SerialNumber; + + std::string ModelName; + }; + + using CPUPowerManagement = struct tagCPUPowerManagement + + { + + bool HasVoltageID; + + bool HasFrequencyID; + + bool HasTempSenseDiode; + }; + + using CPUExtendedFeatures = struct tagCPUExtendedFeatures + + { + + bool Has3DNow; + + bool Has3DNowPlus; + + bool SupportsMP; + + bool HasMMXPlus; + + bool HasSSEMMX; + + unsigned int LogicalProcessorsPerPhysical; + + int APIC_ID; + + CPUPowerManagement PowerManagement; + }; + + using CPUFeatures = struct CPUtagFeatures + + { + + bool HasFPU; + + bool HasTSC; + + bool HasMMX; + + bool HasSSE; + + bool HasSSEFP; + + bool HasSSE2; + + bool HasIA64; + + bool HasAPIC; + + bool HasCMOV; + + bool HasMTRR; + + bool HasACPI; + + bool HasSerial; + + bool HasThermal; + + int CPUSpeed; + + int L1CacheSize; + + int L2CacheSize; + + int L3CacheSize; + + CPUExtendedFeatures ExtendedFeatures; + }; + + enum Manufacturer + { + AMD, + Intel, + NSC, + UMC, + Cyrix, + NexGen, + IDT, + Rise, + Transmeta, + Sun, + IBM, + Motorola, + HP, + Hygon, + UnknownManufacturer + }; + +protected: + // For windows + bool RetrieveCPUFeatures(); + bool RetrieveCPUIdentity(); + bool RetrieveCPUCacheDetails(); + bool RetrieveClassicalCPUCacheDetails(); + bool RetrieveCPUClockSpeed(); + bool RetrieveClassicalCPUClockSpeed(); + bool RetrieveCPUExtendedLevelSupport(int); + bool RetrieveExtendedCPUFeatures(); + bool RetrieveProcessorSerialNumber(); + bool RetrieveCPUPowerManagement(); + bool RetrieveClassicalCPUIdentity(); + bool RetrieveExtendedCPUIdentity(); + + // Processor information + Manufacturer ChipManufacturer; + CPUFeatures Features; + ID ChipID; + float CPUSpeedInMHz; + unsigned int NumberOfLogicalCPU; + unsigned int NumberOfPhysicalCPU; + + void CPUCountWindows(); // For windows + unsigned char GetAPICId(); // For windows + bool IsSMTSupported() const; + static long long GetCyclesDifference(DELAY_FUNC, + unsigned int); // For windows + + // For Linux and Cygwin, /proc/cpuinfo formats are slightly different + bool RetreiveInformationFromCpuInfoFile(); + std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word, + size_t init = 0); + + bool QueryLinuxMemory(); + bool QueryCygwinMemory(); + + static void Delay(unsigned int); + static void DelayOverhead(unsigned int); + + void FindManufacturer(const std::string& family = ""); + + // For Mac + bool ParseSysCtl(); + int CallSwVers(const char* arg, std::string& ver); + void TrimNewline(std::string&); + std::string ExtractValueFromSysCtl(const char* word); + std::string SysCtlBuffer; + + // For Solaris + bool QuerySolarisMemory(); + bool QuerySolarisProcessor(); + std::string ParseValueFromKStat(const char* arguments); + std::string RunProcess(std::vector args); + + // For Haiku OS + bool QueryHaikuInfo(); + + // For QNX + bool QueryQNXMemory(); + bool QueryQNXProcessor(); + + // For OpenBSD, FreeBSD, NetBSD, DragonFly + bool QueryBSDMemory(); + bool QueryBSDProcessor(); + + // For HP-UX + bool QueryHPUXMemory(); + bool QueryHPUXProcessor(); + + // For Microsoft Windows + bool QueryWindowsMemory(); + + // For AIX + bool QueryAIXMemory(); + + bool QueryProcessorBySysconf(); + bool QueryProcessor(); + + // Evaluate the memory information. + bool QueryMemoryBySysconf(); + bool QueryMemory(); + size_t TotalVirtualMemory; + size_t AvailableVirtualMemory; + size_t TotalPhysicalMemory; + size_t AvailablePhysicalMemory; + + size_t CurrentPositionInFile; + + // Operating System information + bool QueryOSInformation(); + std::string OSName; + std::string Hostname; + std::string OSRelease; + std::string OSVersion; + std::string OSPlatform; + bool OSIs64Bit; +}; + +SystemInformation::SystemInformation() +{ + this->Implementation = new SystemInformationImplementation; +} + +SystemInformation::~SystemInformation() +{ + delete this->Implementation; +} + +const char* SystemInformation::GetVendorString() +{ + return this->Implementation->GetVendorString(); +} + +const char* SystemInformation::GetVendorID() +{ + return this->Implementation->GetVendorID(); +} + +std::string SystemInformation::GetTypeID() +{ + return this->Implementation->GetTypeID(); +} + +std::string SystemInformation::GetFamilyID() +{ + return this->Implementation->GetFamilyID(); +} + +std::string SystemInformation::GetModelID() +{ + return this->Implementation->GetModelID(); +} + +std::string SystemInformation::GetModelName() +{ + return this->Implementation->GetModelName(); +} + +std::string SystemInformation::GetSteppingCode() +{ + return this->Implementation->GetSteppingCode(); +} + +const char* SystemInformation::GetExtendedProcessorName() +{ + return this->Implementation->GetExtendedProcessorName(); +} + +const char* SystemInformation::GetProcessorSerialNumber() +{ + return this->Implementation->GetProcessorSerialNumber(); +} + +int SystemInformation::GetProcessorCacheSize() +{ + return this->Implementation->GetProcessorCacheSize(); +} + +unsigned int SystemInformation::GetLogicalProcessorsPerPhysical() +{ + return this->Implementation->GetLogicalProcessorsPerPhysical(); +} + +float SystemInformation::GetProcessorClockFrequency() +{ + return this->Implementation->GetProcessorClockFrequency(); +} + +int SystemInformation::GetProcessorAPICID() +{ + return this->Implementation->GetProcessorAPICID(); +} + +int SystemInformation::GetProcessorCacheXSize(long int l) +{ + return this->Implementation->GetProcessorCacheXSize(l); +} + +bool SystemInformation::DoesCPUSupportFeature(long int i) +{ + return this->Implementation->DoesCPUSupportFeature(i); +} + +std::string SystemInformation::GetCPUDescription() +{ + std::ostringstream oss; + oss << this->GetNumberOfPhysicalCPU() << " core "; + if (this->GetModelName().empty()) { + oss << this->GetProcessorClockFrequency() << " MHz " + << this->GetVendorString() << " " << this->GetExtendedProcessorName(); + } else { + oss << this->GetModelName(); + } + + // remove extra spaces + std::string tmp = oss.str(); + size_t pos; + while ((pos = tmp.find(" ")) != std::string::npos) { + tmp.replace(pos, 2, " "); + } + + return tmp; +} + +const char* SystemInformation::GetOSName() +{ + return this->Implementation->GetOSName(); +} + +const char* SystemInformation::GetHostname() +{ + return this->Implementation->GetHostname(); +} + +std::string SystemInformation::GetFullyQualifiedDomainName() +{ + std::string fqdn; + this->Implementation->GetFullyQualifiedDomainName(fqdn); + return fqdn; +} + +const char* SystemInformation::GetOSRelease() +{ + return this->Implementation->GetOSRelease(); +} + +const char* SystemInformation::GetOSVersion() +{ + return this->Implementation->GetOSVersion(); +} + +const char* SystemInformation::GetOSPlatform() +{ + return this->Implementation->GetOSPlatform(); +} + +int SystemInformation::GetOSIsWindows() +{ +#if defined(_WIN32) + return 1; +#else + return 0; +#endif +} + +int SystemInformation::GetOSIsLinux() +{ +#if defined(__linux) + return 1; +#else + return 0; +#endif +} + +int SystemInformation::GetOSIsApple() +{ +#if defined(__APPLE__) + return 1; +#else + return 0; +#endif +} + +std::string SystemInformation::GetOSDescription() +{ + std::ostringstream oss; + oss << this->GetOSName() << " " << this->GetOSRelease() << " " + << this->GetOSVersion(); + + return oss.str(); +} + +bool SystemInformation::Is64Bits() +{ + return this->Implementation->Is64Bits(); +} + +unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu +{ + return this->Implementation->GetNumberOfLogicalCPU(); +} + +unsigned int SystemInformation::GetNumberOfPhysicalCPU() +{ + return this->Implementation->GetNumberOfPhysicalCPU(); +} + +bool SystemInformation::DoesCPUSupportCPUID() +{ + return this->Implementation->DoesCPUSupportCPUID(); +} + +// Retrieve memory information in MiB. +size_t SystemInformation::GetTotalVirtualMemory() +{ + return this->Implementation->GetTotalVirtualMemory(); +} + +size_t SystemInformation::GetAvailableVirtualMemory() +{ + return this->Implementation->GetAvailableVirtualMemory(); +} + +size_t SystemInformation::GetTotalPhysicalMemory() +{ + return this->Implementation->GetTotalPhysicalMemory(); +} + +size_t SystemInformation::GetAvailablePhysicalMemory() +{ + return this->Implementation->GetAvailablePhysicalMemory(); +} + +std::string SystemInformation::GetMemoryDescription( + const char* hostLimitEnvVarName, const char* procLimitEnvVarName) +{ + std::ostringstream oss; + oss << "Host Total: " << this->GetHostMemoryTotal() + << " KiB, Host Available: " + << this->GetHostMemoryAvailable(hostLimitEnvVarName) + << " KiB, Process Available: " + << this->GetProcMemoryAvailable(hostLimitEnvVarName, procLimitEnvVarName) + << " KiB"; + return oss.str(); +} + +// host memory info in units of KiB. +long long SystemInformation::GetHostMemoryTotal() +{ + return this->Implementation->GetHostMemoryTotal(); +} + +long long SystemInformation::GetHostMemoryAvailable( + const char* hostLimitEnvVarName) +{ + return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName); +} + +long long SystemInformation::GetHostMemoryUsed() +{ + return this->Implementation->GetHostMemoryUsed(); +} + +// process memory info in units of KiB. +long long SystemInformation::GetProcMemoryAvailable( + const char* hostLimitEnvVarName, const char* procLimitEnvVarName) +{ + return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName, + procLimitEnvVarName); +} + +long long SystemInformation::GetProcMemoryUsed() +{ + return this->Implementation->GetProcMemoryUsed(); +} + +double SystemInformation::GetLoadAverage() +{ + return this->Implementation->GetLoadAverage(); +} + +long long SystemInformation::GetProcessId() +{ + return this->Implementation->GetProcessId(); +} + +void SystemInformation::SetStackTraceOnError(int enable) +{ + SystemInformationImplementation::SetStackTraceOnError(enable); +} + +std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath) +{ + return SystemInformationImplementation::GetProgramStack(firstFrame, + wholePath); +} + +/** Run the different checks */ +void SystemInformation::RunCPUCheck() +{ + this->Implementation->RunCPUCheck(); +} + +void SystemInformation::RunOSCheck() +{ + this->Implementation->RunOSCheck(); +} + +void SystemInformation::RunMemoryCheck() +{ + this->Implementation->RunMemoryCheck(); +} + +// SystemInformationImplementation starts here + +#if USE_CPUID +# define STORE_TLBCACHE_INFO(x, y) x = (x < (y)) ? (y) : x +# define TLBCACHE_INFO_UNITS (15) +#endif + +#if USE_ASM_INSTRUCTIONS +# define CLASSICAL_CPU_FREQ_LOOP 10000000 +# define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31 +#endif + +#define INITIAL_APIC_ID_BITS 0xFF000000 +// initial APIC ID for the processor this code is running on. +// Default value = 0xff if HT is not supported + +// Hide implementation details in an anonymous namespace. +namespace { +// ***************************************************************************** +#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) +int LoadLines(FILE* file, std::vector& lines) +{ + // Load each line in the given file into a the vector. + int nRead = 0; + const int bufSize = 1024; + char buf[bufSize] = { '\0' }; + while (!feof(file) && !ferror(file)) { + errno = 0; + if (fgets(buf, bufSize, file) == nullptr) { + if (ferror(file) && (errno == EINTR)) { + clearerr(file); + } + continue; + } + char* pBuf = buf; + while (*pBuf) { + if (*pBuf == '\n') + *pBuf = '\0'; + pBuf += 1; + } + lines.emplace_back(buf); + ++nRead; + } + if (ferror(file)) { + return 0; + } + return nRead; +} + +# if defined(__linux) || defined(__CYGWIN__) +// ***************************************************************************** +int LoadLines(const char* fileName, std::vector& lines) +{ + FILE* file = fopen(fileName, "r"); + if (file == nullptr) { + return 0; + } + int nRead = LoadLines(file, lines); + fclose(file); + return nRead; +} +# endif + +// **************************************************************************** +template +int NameValue(std::vector const& lines, std::string const& name, + T& value) +{ + size_t nLines = lines.size(); + for (size_t i = 0; i < nLines; ++i) { + size_t at = lines[i].find(name); + if (at == std::string::npos) { + continue; + } + std::istringstream is(lines[i].substr(at + name.size())); + is >> value; + return 0; + } + return -1; +} +#endif + +#if defined(__linux) || defined(__CYGWIN__) +// **************************************************************************** +template +int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values) +{ + std::vector fields; + if (!LoadLines(fileName, fields)) { + return -1; + } + int i = 0; + while (fieldNames[i] != nullptr) { + int ierr = NameValue(fields, fieldNames[i], values[i]); + if (ierr) { + return -(i + 2); + } + i += 1; + } + return 0; +} + +// **************************************************************************** +template +int GetFieldFromFile(const char* fileName, const char* fieldName, T& value) +{ + const char* fieldNames[2] = { fieldName, nullptr }; + T values[1] = { T(0) }; + int ierr = GetFieldsFromFile(fileName, fieldNames, values); + if (ierr) { + return ierr; + } + value = values[0]; + return 0; +} +#endif + +// **************************************************************************** +#if defined(__APPLE__) +template +int GetFieldsFromCommand(const char* command, const char** fieldNames, + T* values) +{ + FILE* file = popen(command, "r"); + if (file == nullptr) { + return -1; + } + std::vector fields; + int nl = LoadLines(file, fields); + pclose(file); + if (nl == 0) { + return -1; + } + int i = 0; + while (fieldNames[i] != nullptr) { + int ierr = NameValue(fields, fieldNames[i], values[i]); + if (ierr) { + return -(i + 2); + } + i += 1; + } + return 0; +} +#endif + +// **************************************************************************** +#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo, + void* /*sigContext*/) +{ +# if defined(__linux) || defined(__APPLE__) + std::ostringstream oss; + oss << std::endl + << "=========================================================" + << std::endl + << "Process id " << getpid() << " "; + switch (sigNo) { + case SIGINT: + oss << "Caught SIGINT"; + break; + + case SIGTERM: + oss << "Caught SIGTERM"; + break; + + case SIGABRT: + oss << "Caught SIGABRT"; + break; + + case SIGFPE: + oss << "Caught SIGFPE at " << (sigInfo->si_addr == nullptr ? "0x" : "") + << sigInfo->si_addr << " "; + switch (sigInfo->si_code) { +# if defined(FPE_INTDIV) + case FPE_INTDIV: + oss << "integer division by zero"; + break; +# endif + +# if defined(FPE_INTOVF) + case FPE_INTOVF: + oss << "integer overflow"; + break; +# endif + + case FPE_FLTDIV: + oss << "floating point divide by zero"; + break; + + case FPE_FLTOVF: + oss << "floating point overflow"; + break; + + case FPE_FLTUND: + oss << "floating point underflow"; + break; + + case FPE_FLTRES: + oss << "floating point inexact result"; + break; + + case FPE_FLTINV: + oss << "floating point invalid operation"; + break; + +# if defined(FPE_FLTSUB) + case FPE_FLTSUB: + oss << "floating point subscript out of range"; + break; +# endif + + default: + oss << "code " << sigInfo->si_code; + break; + } + break; + + case SIGSEGV: + oss << "Caught SIGSEGV at " << (sigInfo->si_addr == nullptr ? "0x" : "") + << sigInfo->si_addr << " "; + switch (sigInfo->si_code) { + case SEGV_MAPERR: + oss << "address not mapped to object"; + break; + + case SEGV_ACCERR: + oss << "invalid permission for mapped object"; + break; + + default: + oss << "code " << sigInfo->si_code; + break; + } + break; + + case SIGBUS: + oss << "Caught SIGBUS at " << (sigInfo->si_addr == nullptr ? "0x" : "") + << sigInfo->si_addr << " "; + switch (sigInfo->si_code) { + case BUS_ADRALN: + oss << "invalid address alignment"; + break; + +# if defined(BUS_ADRERR) + case BUS_ADRERR: + oss << "nonexistent physical address"; + break; +# endif + +# if defined(BUS_OBJERR) + case BUS_OBJERR: + oss << "object-specific hardware error"; + break; +# endif + +# if defined(BUS_MCEERR_AR) + case BUS_MCEERR_AR: + oss << "Hardware memory error consumed on a machine check; action " + "required."; + break; +# endif + +# if defined(BUS_MCEERR_AO) + case BUS_MCEERR_AO: + oss << "Hardware memory error detected in process but not consumed; " + "action optional."; + break; +# endif + + default: + oss << "code " << sigInfo->si_code; + break; + } + break; + + case SIGILL: + oss << "Caught SIGILL at " << (sigInfo->si_addr == nullptr ? "0x" : "") + << sigInfo->si_addr << " "; + switch (sigInfo->si_code) { + case ILL_ILLOPC: + oss << "illegal opcode"; + break; + +# if defined(ILL_ILLOPN) + case ILL_ILLOPN: + oss << "illegal operand"; + break; +# endif + +# if defined(ILL_ILLADR) + case ILL_ILLADR: + oss << "illegal addressing mode."; + break; +# endif + + case ILL_ILLTRP: + oss << "illegal trap"; + break; + + case ILL_PRVOPC: + oss << "privileged opcode"; + break; + +# if defined(ILL_PRVREG) + case ILL_PRVREG: + oss << "privileged register"; + break; +# endif + +# if defined(ILL_COPROC) + case ILL_COPROC: + oss << "co-processor error"; + break; +# endif + +# if defined(ILL_BADSTK) + case ILL_BADSTK: + oss << "internal stack error"; + break; +# endif + + default: + oss << "code " << sigInfo->si_code; + break; + } + break; + + default: + oss << "Caught " << sigNo << " code " << sigInfo->si_code; + break; + } + oss << std::endl + << "Program Stack:" << std::endl + << SystemInformationImplementation::GetProgramStack(2, 0) + << "=========================================================" + << std::endl; + std::cerr << oss.str() << std::endl; + + // restore the previously registered handlers + // and abort + SystemInformationImplementation::SetStackTraceOnError(0); + abort(); +# else + // avoid warning C4100 + (void)sigNo; + (void)sigInfo; +# endif +} +#endif + +#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) +# define safes(_arg) ((_arg) ? (_arg) : "???") + +// Description: +// A container for symbol properties. Each instance +// must be Initialized. +class SymbolProperties +{ +public: + SymbolProperties(); + + // Description: + // The SymbolProperties instance must be initialized by + // passing a stack address. + void Initialize(void* address); + + // Description: + // Get the symbol's stack address. + void* GetAddress() const { return this->Address; } + + // Description: + // If not set paths will be removed. eg, from a binary + // or source file. + void SetReportPath(int rp) { this->ReportPath = rp; } + + // Description: + // Set/Get the name of the binary file that the symbol + // is found in. + void SetBinary(const char* binary) { this->Binary = safes(binary); } + + std::string GetBinary() const; + + // Description: + // Set the name of the function that the symbol is found in. + // If c++ demangling is supported it will be demangled. + void SetFunction(const char* function) + { + this->Function = this->Demangle(function); + } + + std::string GetFunction() const { return this->Function; } + + // Description: + // Set/Get the name of the source file where the symbol + // is defined. + void SetSourceFile(const char* sourcefile) + { + this->SourceFile = safes(sourcefile); + } + + std::string GetSourceFile() const + { + return this->GetFileName(this->SourceFile); + } + + // Description: + // Set/Get the line number where the symbol is defined + void SetLineNumber(long linenumber) { this->LineNumber = linenumber; } + long GetLineNumber() const { return this->LineNumber; } + + // Description: + // Set the address where the binary image is mapped + // into memory. + void SetBinaryBaseAddress(void* address) + { + this->BinaryBaseAddress = address; + } + +private: + void* GetRealAddress() const + { + return (void*)((char*)this->Address - (char*)this->BinaryBaseAddress); + } + + std::string GetFileName(const std::string& path) const; + std::string Demangle(const char* symbol) const; + +private: + std::string Binary; + void* BinaryBaseAddress; + void* Address; + std::string SourceFile; + std::string Function; + long LineNumber; + int ReportPath; +}; + +std::ostream& operator<<(std::ostream& os, const SymbolProperties& sp) +{ +# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + os << std::hex << sp.GetAddress() << " : " << sp.GetFunction() << " [(" + << sp.GetBinary() << ") " << sp.GetSourceFile() << ":" << std::dec + << sp.GetLineNumber() << "]"; +# elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + void* addr = sp.GetAddress(); + char** syminfo = backtrace_symbols(&addr, 1); + os << safes(syminfo[0]); + free(syminfo); +# else + (void)os; + (void)sp; +# endif + return os; +} + +SymbolProperties::SymbolProperties() +{ + // not using an initializer list + // to avoid some PGI compiler warnings + this->SetBinary("???"); + this->SetBinaryBaseAddress(nullptr); + this->Address = nullptr; + this->SetSourceFile("???"); + this->SetFunction("???"); + this->SetLineNumber(-1); + this->SetReportPath(0); + // avoid PGI compiler warnings + this->GetRealAddress(); + this->GetFunction(); + this->GetSourceFile(); + this->GetLineNumber(); +} + +std::string SymbolProperties::GetFileName(const std::string& path) const +{ + std::string file(path); + if (!this->ReportPath) { + size_t at = file.rfind('/'); + if (at != std::string::npos) { + file.erase(0, at + 1); + } + } + return file; +} + +std::string SymbolProperties::GetBinary() const +{ +// only linux has proc fs +# if defined(__linux__) + if (this->Binary == "/proc/self/exe") { + std::string binary; + char buf[1024] = { '\0' }; + ssize_t ll = 0; + if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0 && ll < 1024) { + buf[ll] = '\0'; + binary = buf; + } else { + binary = "/proc/self/exe"; + } + return this->GetFileName(binary); + } +# endif + return this->GetFileName(this->Binary); +} + +std::string SymbolProperties::Demangle(const char* symbol) const +{ + std::string result = safes(symbol); +# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) + int status = 0; + size_t bufferLen = 1024; + char* buffer = (char*)malloc(1024); + char* demangledSymbol = + abi::__cxa_demangle(symbol, buffer, &bufferLen, &status); + if (!status) { + result = demangledSymbol; + } + free(buffer); +# else + (void)symbol; +# endif + return result; +} + +void SymbolProperties::Initialize(void* address) +{ + this->Address = address; +# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + // first fallback option can demangle c++ functions + Dl_info info; + int ierr = dladdr(this->Address, &info); + if (ierr && info.dli_sname && info.dli_saddr) { + this->SetBinary(info.dli_fname); + this->SetFunction(info.dli_sname); + } +# else +// second fallback use builtin backtrace_symbols +// to decode the bactrace. +# endif +} +#endif // don't define this class if we're not using it + +#if defined(_WIN32) || defined(__CYGWIN__) +# define KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes +#endif +#if defined(_MSC_VER) && _MSC_VER < 1310 +# undef KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes +#endif +#if defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes) +double calculateCPULoad(unsigned __int64 idleTicks, + unsigned __int64 totalTicks) +{ + static double previousLoad = -0.0; + static unsigned __int64 previousIdleTicks = 0; + static unsigned __int64 previousTotalTicks = 0; + + unsigned __int64 const idleTicksSinceLastTime = + idleTicks - previousIdleTicks; + unsigned __int64 const totalTicksSinceLastTime = + totalTicks - previousTotalTicks; + + double load; + if (previousTotalTicks == 0 || totalTicksSinceLastTime == 0) { + // No new information. Use previous result. + load = previousLoad; + } else { + // Calculate load since last time. + load = 1.0 - double(idleTicksSinceLastTime) / totalTicksSinceLastTime; + + // Smooth if possible. + if (previousLoad > 0) { + load = 0.25 * load + 0.75 * previousLoad; + } + } + + previousLoad = load; + previousIdleTicks = idleTicks; + previousTotalTicks = totalTicks; + + return load; +} + +unsigned __int64 fileTimeToUInt64(FILETIME const& ft) +{ + LARGE_INTEGER out; + out.HighPart = ft.dwHighDateTime; + out.LowPart = ft.dwLowDateTime; + return out.QuadPart; +} +#endif + +} // anonymous namespace + +SystemInformationImplementation::SystemInformationImplementation() +{ + this->TotalVirtualMemory = 0; + this->AvailableVirtualMemory = 0; + this->TotalPhysicalMemory = 0; + this->AvailablePhysicalMemory = 0; + this->CurrentPositionInFile = 0; + this->ChipManufacturer = UnknownManufacturer; + memset(&this->Features, 0, sizeof(CPUFeatures)); + this->ChipID.Type = 0; + this->ChipID.Family = 0; + this->ChipID.Model = 0; + this->ChipID.Revision = 0; + this->ChipID.ExtendedFamily = 0; + this->ChipID.ExtendedModel = 0; + this->CPUSpeedInMHz = 0; + this->NumberOfLogicalCPU = 0; + this->NumberOfPhysicalCPU = 0; + this->OSName = ""; + this->Hostname = ""; + this->OSRelease = ""; + this->OSVersion = ""; + this->OSPlatform = ""; + this->OSIs64Bit = (sizeof(void*) == 8); +} + +void SystemInformationImplementation::RunCPUCheck() +{ +#ifdef _WIN32 + // Check to see if this processor supports CPUID. + bool supportsCPUID = DoesCPUSupportCPUID(); + + if (supportsCPUID) { + // Retrieve the CPU details. + RetrieveCPUIdentity(); + this->FindManufacturer(); + RetrieveCPUFeatures(); + } + + // These two may be called without support for the CPUID instruction. + // (But if the instruction is there, they should be called *after* + // the above call to RetrieveCPUIdentity... that's why the two if + // blocks exist with the same "if (supportsCPUID)" logic... + // + if (!RetrieveCPUClockSpeed()) { + RetrieveClassicalCPUClockSpeed(); + } + + if (supportsCPUID) { + // Retrieve cache information. + if (!RetrieveCPUCacheDetails()) { + RetrieveClassicalCPUCacheDetails(); + } + + // Retrieve the extended CPU details. + if (!RetrieveExtendedCPUIdentity()) { + RetrieveClassicalCPUIdentity(); + } + + RetrieveExtendedCPUFeatures(); + RetrieveCPUPowerManagement(); + + // Now attempt to retrieve the serial number (if possible). + RetrieveProcessorSerialNumber(); + } + + this->CPUCountWindows(); + +#elif defined(__APPLE__) + this->ParseSysCtl(); +#elif defined(__SVR4) && defined(__sun) + this->QuerySolarisProcessor(); +#elif defined(__HAIKU__) + this->QueryHaikuInfo(); +#elif defined(__QNX__) + this->QueryQNXProcessor(); +#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) + this->QueryBSDProcessor(); +#elif defined(__hpux) + this->QueryHPUXProcessor(); +#elif defined(__linux) || defined(__CYGWIN__) + this->RetreiveInformationFromCpuInfoFile(); +#else + this->QueryProcessor(); +#endif +} + +void SystemInformationImplementation::RunOSCheck() +{ + this->QueryOSInformation(); +} + +void SystemInformationImplementation::RunMemoryCheck() +{ +#if defined(__APPLE__) + this->ParseSysCtl(); +#elif defined(__SVR4) && defined(__sun) + this->QuerySolarisMemory(); +#elif defined(__HAIKU__) + this->QueryHaikuInfo(); +#elif defined(__QNX__) + this->QueryQNXMemory(); +#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) + this->QueryBSDMemory(); +#elif defined(__CYGWIN__) + this->QueryCygwinMemory(); +#elif defined(_WIN32) + this->QueryWindowsMemory(); +#elif defined(__hpux) + this->QueryHPUXMemory(); +#elif defined(__linux) + this->QueryLinuxMemory(); +#elif defined(_AIX) + this->QueryAIXMemory(); +#else + this->QueryMemory(); +#endif +} + +/** Get the vendor string */ +const char* SystemInformationImplementation::GetVendorString() const +{ + return this->ChipID.Vendor.c_str(); +} + +/** Get the OS Name */ +const char* SystemInformationImplementation::GetOSName() +{ + return this->OSName.c_str(); +} + +/** Get the hostname */ +const char* SystemInformationImplementation::GetHostname() +{ + if (this->Hostname.empty()) { + this->Hostname = "localhost"; +#if defined(_WIN32) + WORD wVersionRequested; + WSADATA wsaData; + char name[255]; + wVersionRequested = MAKEWORD(2, 0); + if (WSAStartup(wVersionRequested, &wsaData) == 0) { + gethostname(name, sizeof(name)); + WSACleanup(); + } + this->Hostname = name; +#else + struct utsname unameInfo; + int errorFlag = uname(&unameInfo); + if (errorFlag == 0) { + this->Hostname = unameInfo.nodename; + } +#endif + } + return this->Hostname.c_str(); +} + +/** Get the FQDN */ +int SystemInformationImplementation::GetFullyQualifiedDomainName( + std::string& fqdn) +{ + // in the event of absolute failure return localhost. + fqdn = "localhost"; + +#if defined(_WIN32) + int ierr; + // TODO - a more robust implementation for windows, see comments + // in unix implementation. + WSADATA wsaData; + WORD ver = MAKEWORD(2, 0); + ierr = WSAStartup(ver, &wsaData); + if (ierr) { + return -1; + } + + char base[256] = { '\0' }; + ierr = gethostname(base, 256); + if (ierr) { + WSACleanup(); + return -2; + } + fqdn = base; + + HOSTENT* hent = gethostbyname(base); + if (hent) { + fqdn = hent->h_name; + } + + WSACleanup(); + return 0; + +#elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN) + // gethostname typical returns an alias for loopback interface + // we want the fully qualified domain name. Because there are + // any number of interfaces on this system we look for the + // first of these that contains the name returned by gethostname + // and is longer. failing that we return gethostname and indicate + // with a failure code. Return of a failure code is not necessarily + // an indication of an error. for instance gethostname may return + // the fully qualified domain name, or there may not be one if the + // system lives on a private network such as in the case of a cluster + // node. + + int ierr = 0; + char base[NI_MAXHOST]; + ierr = gethostname(base, NI_MAXHOST); + if (ierr) { + return -1; + } + size_t baseSize = strlen(base); + fqdn = base; + + struct ifaddrs* ifas; + struct ifaddrs* ifa; + ierr = getifaddrs(&ifas); + if (ierr) { + return -2; + } + + for (ifa = ifas; ifa != nullptr; ifa = ifa->ifa_next) { + int fam = ifa->ifa_addr ? ifa->ifa_addr->sa_family : -1; + // Skip Loopback interfaces + if (((fam == AF_INET) || (fam == AF_INET6)) && + !(ifa->ifa_flags & IFF_LOOPBACK)) { + char host[NI_MAXHOST] = { '\0' }; + + const size_t addrlen = (fam == AF_INET ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6)); + + ierr = getnameinfo(ifa->ifa_addr, static_cast(addrlen), host, + NI_MAXHOST, nullptr, 0, NI_NAMEREQD); + if (ierr) { + // don't report the failure now since we may succeed on another + // interface. If all attempts fail then return the failure code. + ierr = -3; + continue; + } + + std::string candidate = host; + if ((candidate.find(base) != std::string::npos) && + baseSize < candidate.size()) { + // success, stop now. + ierr = 0; + fqdn = candidate; + break; + } + } + } + freeifaddrs(ifas); + + return ierr; +#else + /* TODO: Implement on more platforms. */ + fqdn = this->GetHostname(); + return -1; +#endif +} + +/** Get the OS release */ +const char* SystemInformationImplementation::GetOSRelease() +{ + return this->OSRelease.c_str(); +} + +/** Get the OS version */ +const char* SystemInformationImplementation::GetOSVersion() +{ + return this->OSVersion.c_str(); +} + +/** Get the OS platform */ +const char* SystemInformationImplementation::GetOSPlatform() +{ + return this->OSPlatform.c_str(); +} + +/** Get the vendor ID */ +const char* SystemInformationImplementation::GetVendorID() +{ + // Return the vendor ID. + switch (this->ChipManufacturer) { + case Intel: + return "Intel Corporation"; + case AMD: + return "Advanced Micro Devices"; + case NSC: + return "National Semiconductor"; + case Cyrix: + return "Cyrix Corp., VIA Inc."; + case NexGen: + return "NexGen Inc., Advanced Micro Devices"; + case IDT: + return "IDT\\Centaur, Via Inc."; + case UMC: + return "United Microelectronics Corp."; + case Rise: + return "Rise"; + case Transmeta: + return "Transmeta"; + case Sun: + return "Sun Microelectronics"; + case IBM: + return "IBM"; + case Motorola: + return "Motorola"; + case HP: + return "Hewlett-Packard"; + case Hygon: + return "Chengdu Haiguang IC Design Co., Ltd."; + case UnknownManufacturer: + default: + return "Unknown Manufacturer"; + } +} + +/** Return the type ID of the CPU */ +std::string SystemInformationImplementation::GetTypeID() const +{ + std::ostringstream str; + str << this->ChipID.Type; + return str.str(); +} + +/** Return the family of the CPU present */ +std::string SystemInformationImplementation::GetFamilyID() const +{ + std::ostringstream str; + str << this->ChipID.Family; + return str.str(); +} + +// Return the model of CPU present */ +std::string SystemInformationImplementation::GetModelID() const +{ + std::ostringstream str; + str << this->ChipID.Model; + return str.str(); +} + +// Return the model name of CPU present */ +std::string SystemInformationImplementation::GetModelName() const +{ + return this->ChipID.ModelName; +} + +/** Return the stepping code of the CPU present. */ +std::string SystemInformationImplementation::GetSteppingCode() const +{ + std::ostringstream str; + str << this->ChipID.Revision; + return str.str(); +} + +/** Return the stepping code of the CPU present. */ +const char* SystemInformationImplementation::GetExtendedProcessorName() const +{ + return this->ChipID.ProcessorName.c_str(); +} + +/** Return the serial number of the processor + * in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */ +const char* SystemInformationImplementation::GetProcessorSerialNumber() const +{ + return this->ChipID.SerialNumber.c_str(); +} + +/** Return the logical processors per physical */ +unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical() + const +{ + return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical; +} + +/** Return the processor clock frequency. */ +float SystemInformationImplementation::GetProcessorClockFrequency() const +{ + return this->CPUSpeedInMHz; +} + +/** Return the APIC ID. */ +int SystemInformationImplementation::GetProcessorAPICID() const +{ + return this->Features.ExtendedFeatures.APIC_ID; +} + +/** Return the L1 cache size. */ +int SystemInformationImplementation::GetProcessorCacheSize() const +{ + return this->Features.L1CacheSize; +} + +/** Return the chosen cache size. */ +int SystemInformationImplementation::GetProcessorCacheXSize( + long int dwCacheID) const +{ + switch (dwCacheID) { + case SystemInformation::CPU_FEATURE_L1CACHE: + return this->Features.L1CacheSize; + case SystemInformation::CPU_FEATURE_L2CACHE: + return this->Features.L2CacheSize; + case SystemInformation::CPU_FEATURE_L3CACHE: + return this->Features.L3CacheSize; + } + return -1; +} + +bool SystemInformationImplementation::DoesCPUSupportFeature( + long int dwFeature) const +{ + bool bHasFeature = false; + + // Check for MMX instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_MMX) != 0) && + this->Features.HasMMX) + bHasFeature = true; + + // Check for MMX+ instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_MMX_PLUS) != 0) && + this->Features.ExtendedFeatures.HasMMXPlus) + bHasFeature = true; + + // Check for SSE FP instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_SSE) != 0) && + this->Features.HasSSE) + bHasFeature = true; + + // Check for SSE FP instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_FP) != 0) && + this->Features.HasSSEFP) + bHasFeature = true; + + // Check for SSE MMX instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_MMX) != 0) && + this->Features.ExtendedFeatures.HasSSEMMX) + bHasFeature = true; + + // Check for SSE2 instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_SSE2) != 0) && + this->Features.HasSSE2) + bHasFeature = true; + + // Check for 3DNow! instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW) != 0) && + this->Features.ExtendedFeatures.Has3DNow) + bHasFeature = true; + + // Check for 3DNow+ instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW_PLUS) != 0) && + this->Features.ExtendedFeatures.Has3DNowPlus) + bHasFeature = true; + + // Check for IA64 instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_IA64) != 0) && + this->Features.HasIA64) + bHasFeature = true; + + // Check for MP capable. + if (((dwFeature & SystemInformation::CPU_FEATURE_MP_CAPABLE) != 0) && + this->Features.ExtendedFeatures.SupportsMP) + bHasFeature = true; + + // Check for a serial number for the processor. + if (((dwFeature & SystemInformation::CPU_FEATURE_SERIALNUMBER) != 0) && + this->Features.HasSerial) + bHasFeature = true; + + // Check for a local APIC in the processor. + if (((dwFeature & SystemInformation::CPU_FEATURE_APIC) != 0) && + this->Features.HasAPIC) + bHasFeature = true; + + // Check for CMOV instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_CMOV) != 0) && + this->Features.HasCMOV) + bHasFeature = true; + + // Check for MTRR instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_MTRR) != 0) && + this->Features.HasMTRR) + bHasFeature = true; + + // Check for L1 cache size. + if (((dwFeature & SystemInformation::CPU_FEATURE_L1CACHE) != 0) && + (this->Features.L1CacheSize != -1)) + bHasFeature = true; + + // Check for L2 cache size. + if (((dwFeature & SystemInformation::CPU_FEATURE_L2CACHE) != 0) && + (this->Features.L2CacheSize != -1)) + bHasFeature = true; + + // Check for L3 cache size. + if (((dwFeature & SystemInformation::CPU_FEATURE_L3CACHE) != 0) && + (this->Features.L3CacheSize != -1)) + bHasFeature = true; + + // Check for ACPI capability. + if (((dwFeature & SystemInformation::CPU_FEATURE_ACPI) != 0) && + this->Features.HasACPI) + bHasFeature = true; + + // Check for thermal monitor support. + if (((dwFeature & SystemInformation::CPU_FEATURE_THERMALMONITOR) != 0) && + this->Features.HasThermal) + bHasFeature = true; + + // Check for temperature sensing diode support. + if (((dwFeature & SystemInformation::CPU_FEATURE_TEMPSENSEDIODE) != 0) && + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) + bHasFeature = true; + + // Check for frequency ID support. + if (((dwFeature & SystemInformation::CPU_FEATURE_FREQUENCYID) != 0) && + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID) + bHasFeature = true; + + // Check for voltage ID support. + if (((dwFeature & SystemInformation::CPU_FEATURE_VOLTAGEID_FREQUENCY) != + 0) && + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID) + bHasFeature = true; + + // Check for FPU support. + if (((dwFeature & SystemInformation::CPU_FEATURE_FPU) != 0) && + this->Features.HasFPU) + bHasFeature = true; + + return bHasFeature; +} + +void SystemInformationImplementation::Delay(unsigned int uiMS) +{ +#ifdef _WIN32 + LARGE_INTEGER Frequency, StartCounter, EndCounter; + __int64 x; + + // Get the frequency of the high performance counter. + if (!QueryPerformanceFrequency(&Frequency)) + return; + x = Frequency.QuadPart / 1000 * uiMS; + + // Get the starting position of the counter. + QueryPerformanceCounter(&StartCounter); + + do { + // Get the ending position of the counter. + QueryPerformanceCounter(&EndCounter); + } while (EndCounter.QuadPart - StartCounter.QuadPart < x); +#endif + (void)uiMS; +} + +bool SystemInformationImplementation::DoesCPUSupportCPUID() +{ +#if USE_CPUID + int dummy[4] = { 0, 0, 0, 0 }; + +# if USE_ASM_INSTRUCTIONS + return call_cpuid(0, dummy); +# else + call_cpuid(0, dummy); + return dummy[0] || dummy[1] || dummy[2] || dummy[3]; +# endif +#else + // Assume no cpuid instruction. + return false; +#endif +} + +bool SystemInformationImplementation::RetrieveCPUFeatures() +{ +#if USE_CPUID + int cpuinfo[4] = { 0, 0, 0, 0 }; + + if (!call_cpuid(1, cpuinfo)) { + return false; + } + + // Retrieve the features of CPU present. + this->Features.HasFPU = + ((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0 + this->Features.HasTSC = + ((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4 + this->Features.HasAPIC = + ((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9 + this->Features.HasMTRR = + ((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12 + this->Features.HasCMOV = + ((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15 + this->Features.HasSerial = + ((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18 + this->Features.HasACPI = + ((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22 + this->Features.HasMMX = + ((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23 + this->Features.HasSSE = + ((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25 + this->Features.HasSSE2 = + ((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26 + this->Features.HasThermal = + ((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29 + this->Features.HasIA64 = + ((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30 + +# if USE_ASM_INSTRUCTIONS + // Retrieve extended SSE capabilities if SSE is available. + if (this->Features.HasSSE) { + + // Attempt to __try some SSE FP instructions. + __try { + // Perform: orps xmm0, xmm0 + _asm + { + _emit 0x0f + _emit 0x56 + _emit 0xc0 + } + + // SSE FP capable processor. + this->Features.HasSSEFP = true; + } __except (1) { + // bad instruction - processor or OS cannot handle SSE FP. + this->Features.HasSSEFP = false; + } + } else { + // Set the advanced SSE capabilities to not available. + this->Features.HasSSEFP = false; + } +# else + this->Features.HasSSEFP = false; +# endif + + // Retrieve Intel specific extended features. + if (this->ChipManufacturer == Intel) { + bool SupportsSMT = + ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: SMT --> Bit 28 + + if ((SupportsSMT) && (this->Features.HasAPIC)) { + // Retrieve APIC information if there is one present. + this->Features.ExtendedFeatures.APIC_ID = + ((cpuinfo[1] & 0xFF000000) >> 24); + } + } + + return true; + +#else + return false; +#endif +} + +/** Find the manufacturer given the vendor id */ +void SystemInformationImplementation::FindManufacturer( + const std::string& family) +{ + if (this->ChipID.Vendor == "GenuineIntel") + this->ChipManufacturer = Intel; // Intel Corp. + else if (this->ChipID.Vendor == "UMC UMC UMC ") + this->ChipManufacturer = UMC; // United Microelectronics Corp. + else if (this->ChipID.Vendor == "AuthenticAMD") + this->ChipManufacturer = AMD; // Advanced Micro Devices + else if (this->ChipID.Vendor == "AMD ISBETTER") + this->ChipManufacturer = AMD; // Advanced Micro Devices (1994) + else if (this->ChipID.Vendor == "HygonGenuine") + this->ChipManufacturer = Hygon; // Chengdu Haiguang IC Design Co., Ltd. + else if (this->ChipID.Vendor == "CyrixInstead") + this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc. + else if (this->ChipID.Vendor == "NexGenDriven") + this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD) + else if (this->ChipID.Vendor == "CentaurHauls") + this->ChipManufacturer = IDT; // IDT/Centaur (now VIA) + else if (this->ChipID.Vendor == "RiseRiseRise") + this->ChipManufacturer = Rise; // Rise + else if (this->ChipID.Vendor == "GenuineTMx86") + this->ChipManufacturer = Transmeta; // Transmeta + else if (this->ChipID.Vendor == "TransmetaCPU") + this->ChipManufacturer = Transmeta; // Transmeta + else if (this->ChipID.Vendor == "Geode By NSC") + this->ChipManufacturer = NSC; // National Semiconductor + else if (this->ChipID.Vendor == "Sun") + this->ChipManufacturer = Sun; // Sun Microelectronics + else if (this->ChipID.Vendor == "IBM") + this->ChipManufacturer = IBM; // IBM Microelectronics + else if (this->ChipID.Vendor == "Hewlett-Packard") + this->ChipManufacturer = HP; // Hewlett-Packard + else if (this->ChipID.Vendor == "Motorola") + this->ChipManufacturer = Motorola; // Motorola Microelectronics + else if (family.compare(0, 7, "PA-RISC") == 0) + this->ChipManufacturer = HP; // Hewlett-Packard + else + this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUIdentity() +{ +#if USE_CPUID + int localCPUVendor[4]; + int localCPUSignature[4]; + + if (!call_cpuid(0, localCPUVendor)) { + return false; + } + if (!call_cpuid(1, localCPUSignature)) { + return false; + } + + // Process the returned information. + // ; eax = 0 --> eax: maximum value of CPUID instruction. + // ; ebx: part 1 of 3; CPU signature. + // ; edx: part 2 of 3; CPU signature. + // ; ecx: part 3 of 3; CPU signature. + char vbuf[13]; + memcpy(&(vbuf[0]), &(localCPUVendor[1]), sizeof(int)); + memcpy(&(vbuf[4]), &(localCPUVendor[3]), sizeof(int)); + memcpy(&(vbuf[8]), &(localCPUVendor[2]), sizeof(int)); + vbuf[12] = '\0'; + this->ChipID.Vendor = vbuf; + + // Retrieve the family of CPU present. + // ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, + // bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision + // ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, + // 15..8 - CFLUSH chunk size , 7..0 - brand ID + // ; edx: CPU feature flags + this->ChipID.ExtendedFamily = + ((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used + this->ChipID.ExtendedModel = + ((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used + this->ChipID.Type = + ((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used + this->ChipID.Family = + ((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used + this->ChipID.Model = + ((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used + this->ChipID.Revision = + ((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used + + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUCacheDetails() +{ +#if USE_CPUID + int L1Cache[4] = { 0, 0, 0, 0 }; + int L2Cache[4] = { 0, 0, 0, 0 }; + + // Check to see if what we are about to do is supported... + if (RetrieveCPUExtendedLevelSupport(0x80000005)) { + if (!call_cpuid(0x80000005, L1Cache)) { + return false; + } + // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as + // data cache size from edx: bits 31..24. + this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24); + this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24); + } else { + // Store -1 to indicate the cache could not be queried. + this->Features.L1CacheSize = -1; + } + + // Check to see if what we are about to do is supported... + if (RetrieveCPUExtendedLevelSupport(0x80000006)) { + if (!call_cpuid(0x80000006, L2Cache)) { + return false; + } + // Save the L2 unified cache size (in KB) from ecx: bits 31..16. + this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16); + } else { + // Store -1 to indicate the cache could not be queried. + this->Features.L2CacheSize = -1; + } + + // Define L3 as being not present as we cannot test for it. + this->Features.L3CacheSize = -1; + +#endif + + // Return failure if we cannot detect either cache with this method. + return ((this->Features.L1CacheSize == -1) && + (this->Features.L2CacheSize == -1)) + ? false + : true; +} + +/** */ +bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails() +{ +#if USE_CPUID + int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, + L2Unified = -1, L3Unified = -1; + int TLBCacheData[4] = { 0, 0, 0, 0 }; + int TLBPassCounter = 0; + int TLBCacheUnit = 0; + + do { + if (!call_cpuid(2, TLBCacheData)) { + return false; + } + + int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16); + (void)bob; + // Process the returned TLB and cache information. + for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter++) { + // First of all - decide which unit we are dealing with. + switch (nCounter) { + // eax: bits 8..15 : bits 16..23 : bits 24..31 + case 0: + TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); + break; + case 1: + TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); + break; + case 2: + TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); + break; + + // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 + case 3: + TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); + break; + case 4: + TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); + break; + case 5: + TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); + break; + case 6: + TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); + break; + + // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 + case 7: + TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); + break; + case 8: + TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); + break; + case 9: + TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); + break; + case 10: + TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); + break; + + // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 + case 11: + TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); + break; + case 12: + TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); + break; + case 13: + TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); + break; + case 14: + TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); + break; + + // Default case - an error has occurred. + default: + return false; + } + + // Now process the resulting unit to see what it means.... + switch (TLBCacheUnit) { + case 0x00: + break; + case 0x01: + STORE_TLBCACHE_INFO(TLBCode, 4); + break; + case 0x02: + STORE_TLBCACHE_INFO(TLBCode, 4096); + break; + case 0x03: + STORE_TLBCACHE_INFO(TLBData, 4); + break; + case 0x04: + STORE_TLBCACHE_INFO(TLBData, 4096); + break; + case 0x06: + STORE_TLBCACHE_INFO(L1Code, 8); + break; + case 0x08: + STORE_TLBCACHE_INFO(L1Code, 16); + break; + case 0x0a: + STORE_TLBCACHE_INFO(L1Data, 8); + break; + case 0x0c: + STORE_TLBCACHE_INFO(L1Data, 16); + break; + case 0x10: + STORE_TLBCACHE_INFO(L1Data, 16); + break; // <-- FIXME: IA-64 Only + case 0x15: + STORE_TLBCACHE_INFO(L1Code, 16); + break; // <-- FIXME: IA-64 Only + case 0x1a: + STORE_TLBCACHE_INFO(L2Unified, 96); + break; // <-- FIXME: IA-64 Only + case 0x22: + STORE_TLBCACHE_INFO(L3Unified, 512); + break; + case 0x23: + STORE_TLBCACHE_INFO(L3Unified, 1024); + break; + case 0x25: + STORE_TLBCACHE_INFO(L3Unified, 2048); + break; + case 0x29: + STORE_TLBCACHE_INFO(L3Unified, 4096); + break; + case 0x39: + STORE_TLBCACHE_INFO(L2Unified, 128); + break; + case 0x3c: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x40: + STORE_TLBCACHE_INFO(L2Unified, 0); + break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 + // core). + case 0x41: + STORE_TLBCACHE_INFO(L2Unified, 128); + break; + case 0x42: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x43: + STORE_TLBCACHE_INFO(L2Unified, 512); + break; + case 0x44: + STORE_TLBCACHE_INFO(L2Unified, 1024); + break; + case 0x45: + STORE_TLBCACHE_INFO(L2Unified, 2048); + break; + case 0x50: + STORE_TLBCACHE_INFO(TLBCode, 4096); + break; + case 0x51: + STORE_TLBCACHE_INFO(TLBCode, 4096); + break; + case 0x52: + STORE_TLBCACHE_INFO(TLBCode, 4096); + break; + case 0x5b: + STORE_TLBCACHE_INFO(TLBData, 4096); + break; + case 0x5c: + STORE_TLBCACHE_INFO(TLBData, 4096); + break; + case 0x5d: + STORE_TLBCACHE_INFO(TLBData, 4096); + break; + case 0x66: + STORE_TLBCACHE_INFO(L1Data, 8); + break; + case 0x67: + STORE_TLBCACHE_INFO(L1Data, 16); + break; + case 0x68: + STORE_TLBCACHE_INFO(L1Data, 32); + break; + case 0x70: + STORE_TLBCACHE_INFO(L1Trace, 12); + break; + case 0x71: + STORE_TLBCACHE_INFO(L1Trace, 16); + break; + case 0x72: + STORE_TLBCACHE_INFO(L1Trace, 32); + break; + case 0x77: + STORE_TLBCACHE_INFO(L1Code, 16); + break; // <-- FIXME: IA-64 Only + case 0x79: + STORE_TLBCACHE_INFO(L2Unified, 128); + break; + case 0x7a: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x7b: + STORE_TLBCACHE_INFO(L2Unified, 512); + break; + case 0x7c: + STORE_TLBCACHE_INFO(L2Unified, 1024); + break; + case 0x7e: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x81: + STORE_TLBCACHE_INFO(L2Unified, 128); + break; + case 0x82: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x83: + STORE_TLBCACHE_INFO(L2Unified, 512); + break; + case 0x84: + STORE_TLBCACHE_INFO(L2Unified, 1024); + break; + case 0x85: + STORE_TLBCACHE_INFO(L2Unified, 2048); + break; + case 0x88: + STORE_TLBCACHE_INFO(L3Unified, 2048); + break; // <-- FIXME: IA-64 Only + case 0x89: + STORE_TLBCACHE_INFO(L3Unified, 4096); + break; // <-- FIXME: IA-64 Only + case 0x8a: + STORE_TLBCACHE_INFO(L3Unified, 8192); + break; // <-- FIXME: IA-64 Only + case 0x8d: + STORE_TLBCACHE_INFO(L3Unified, 3096); + break; // <-- FIXME: IA-64 Only + case 0x90: + STORE_TLBCACHE_INFO(TLBCode, 262144); + break; // <-- FIXME: IA-64 Only + case 0x96: + STORE_TLBCACHE_INFO(TLBCode, 262144); + break; // <-- FIXME: IA-64 Only + case 0x9b: + STORE_TLBCACHE_INFO(TLBCode, 262144); + break; // <-- FIXME: IA-64 Only + + // Default case - an error has occurred. + default: + return false; + } + } + + // Increment the TLB pass counter. + TLBPassCounter++; + } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter); + + // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... + if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1)) { + this->Features.L1CacheSize = -1; + } else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1)) { + this->Features.L1CacheSize = L1Trace; + } else if ((L1Code != -1) && (L1Data == -1)) { + this->Features.L1CacheSize = L1Code; + } else if ((L1Code == -1) && (L1Data != -1)) { + this->Features.L1CacheSize = L1Data; + } else if ((L1Code != -1) && (L1Data != -1)) { + this->Features.L1CacheSize = L1Code + L1Data; + } else { + this->Features.L1CacheSize = -1; + } + + // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... + if (L2Unified == -1) { + this->Features.L2CacheSize = -1; + } else { + this->Features.L2CacheSize = L2Unified; + } + + // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... + if (L3Unified == -1) { + this->Features.L3CacheSize = -1; + } else { + this->Features.L3CacheSize = L3Unified; + } + + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUClockSpeed() +{ + bool retrieved = false; + +#if defined(_WIN32) + unsigned int uiRepetitions = 1; + unsigned int uiMSecPerRepetition = 50; + __int64 i64Total = 0; + __int64 i64Overhead = 0; + + // Check if the TSC implementation works at all + if (this->Features.HasTSC && + GetCyclesDifference(SystemInformationImplementation::Delay, + uiMSecPerRepetition) > 0) { + for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter++) { + i64Total += GetCyclesDifference(SystemInformationImplementation::Delay, + uiMSecPerRepetition); + i64Overhead += GetCyclesDifference( + SystemInformationImplementation::DelayOverhead, uiMSecPerRepetition); + } + + // Calculate the MHz speed. + i64Total -= i64Overhead; + i64Total /= uiRepetitions; + i64Total /= uiMSecPerRepetition; + i64Total /= 1000; + + // Save the CPU speed. + this->CPUSpeedInMHz = (float)i64Total; + + retrieved = true; + } + + // If RDTSC is not supported, we fallback to trying to read this value + // from the registry: + if (!retrieved) { + HKEY hKey = nullptr; + LONG err = + RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, + KEY_READ, &hKey); + + if (ERROR_SUCCESS == err) { + DWORD dwType = 0; + DWORD data = 0; + DWORD dwSize = sizeof(DWORD); + + err = + RegQueryValueExW(hKey, L"~MHz", 0, &dwType, (LPBYTE)&data, &dwSize); + + if (ERROR_SUCCESS == err) { + this->CPUSpeedInMHz = (float)data; + retrieved = true; + } + + RegCloseKey(hKey); + hKey = nullptr; + } + } +#endif + + return retrieved; +} + +/** */ +bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed() +{ +#if USE_ASM_INSTRUCTIONS + LARGE_INTEGER liStart, liEnd, liCountsPerSecond; + double dFrequency, dDifference; + + // Attempt to get a starting tick count. + QueryPerformanceCounter(&liStart); + + __try { + _asm { + mov eax, 0x80000000 + mov ebx, CLASSICAL_CPU_FREQ_LOOP + Timer_Loop: + bsf ecx,eax + dec ebx + jnz Timer_Loop + } + } __except (1) { + return false; + } + + // Attempt to get a starting tick count. + QueryPerformanceCounter(&liEnd); + + // Get the difference... NB: This is in seconds.... + QueryPerformanceFrequency(&liCountsPerSecond); + dDifference = (((double)liEnd.QuadPart - (double)liStart.QuadPart) / + (double)liCountsPerSecond.QuadPart); + + // Calculate the clock speed. + if (this->ChipID.Family == 3) { + // 80386 processors.... Loop time is 115 cycles! + dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000); + } else if (this->ChipID.Family == 4) { + // 80486 processors.... Loop time is 47 cycles! + dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000); + } else if (this->ChipID.Family == 5) { + // Pentium processors.... Loop time is 43 cycles! + dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000); + } + + // Save the clock speed. + this->Features.CPUSpeed = (int)dFrequency; + + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport( + int CPULevelToCheck) +{ + int cpuinfo[4] = { 0, 0, 0, 0 }; + + // The extended CPUID is supported by various vendors starting with the + // following CPU models: + // + // Manufacturer & Chip Name | Family Model Revision + // + // AMD K6, K6-2 | 5 6 x + // Cyrix GXm, Cyrix III "Joshua" | 5 4 x + // IDT C6-2 | 5 8 x + // VIA Cyrix III | 6 5 x + // Transmeta Crusoe | 5 x x + // Intel Pentium 4 | f x x + // + + // We check to see if a supported processor is present... + if (this->ChipManufacturer == AMD) { + if (this->ChipID.Family < 5) + return false; + if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6)) + return false; + } else if (this->ChipManufacturer == Cyrix) { + if (this->ChipID.Family < 5) + return false; + if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4)) + return false; + if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5)) + return false; + } else if (this->ChipManufacturer == IDT) { + if (this->ChipID.Family < 5) + return false; + if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8)) + return false; + } else if (this->ChipManufacturer == Transmeta) { + if (this->ChipID.Family < 5) + return false; + } else if (this->ChipManufacturer == Intel) { + if (this->ChipID.Family < 0xf) { + return false; + } + } + +#if USE_CPUID + if (!call_cpuid(0x80000000, cpuinfo)) { + return false; + } +#endif + + // Now we have to check the level wanted vs level returned... + int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF); + int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF); + + // Check to see if the level provided is supported... + if (nLevelWanted > nLevelReturn) { + return false; + } + + return true; +} + +/** */ +bool SystemInformationImplementation::RetrieveExtendedCPUFeatures() +{ + + // Check that we are not using an Intel processor as it does not support + // this. + if (this->ChipManufacturer == Intel) { + return false; + } + + // Check to see if what we are about to do is supported... + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000001))) { + return false; + } + +#if USE_CPUID + int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 }; + + if (!call_cpuid(0x80000001, localCPUExtendedFeatures)) { + return false; + } + + // Retrieve the extended features of CPU present. + this->Features.ExtendedFeatures.Has3DNow = + ((localCPUExtendedFeatures[3] & 0x80000000) != + 0); // 3DNow Present --> Bit 31. + this->Features.ExtendedFeatures.Has3DNowPlus = + ((localCPUExtendedFeatures[3] & 0x40000000) != + 0); // 3DNow+ Present -- > Bit 30. + this->Features.ExtendedFeatures.HasSSEMMX = + ((localCPUExtendedFeatures[3] & 0x00400000) != + 0); // SSE MMX Present --> Bit 22. + this->Features.ExtendedFeatures.SupportsMP = + ((localCPUExtendedFeatures[3] & 0x00080000) != + 0); // MP Capable -- > Bit 19. + + // Retrieve AMD specific extended features. + if (this->ChipManufacturer == AMD || this->ChipManufacturer == Hygon) { + this->Features.ExtendedFeatures.HasMMXPlus = + ((localCPUExtendedFeatures[3] & 0x00400000) != + 0); // AMD specific: MMX-SSE --> Bit 22 + } + + // Retrieve Cyrix specific extended features. + if (this->ChipManufacturer == Cyrix) { + this->Features.ExtendedFeatures.HasMMXPlus = + ((localCPUExtendedFeatures[3] & 0x01000000) != + 0); // Cyrix specific: Extended MMX --> Bit 24 + } + + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveProcessorSerialNumber() +{ + // Check to see if the processor supports the processor serial number. + if (!this->Features.HasSerial) { + return false; + } + +#if USE_CPUID + int SerialNumber[4]; + + if (!call_cpuid(3, SerialNumber)) { + return false; + } + + // Process the returned information. + // ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: + // Transmeta only ?!? + // ; ecx: middle 32 bits are the processor signature bits + // ; edx: bottom 32 bits are the processor signature bits + char sn[128]; + sprintf(sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x", + ((SerialNumber[1] & 0xff000000) >> 24), + ((SerialNumber[1] & 0x00ff0000) >> 16), + ((SerialNumber[1] & 0x0000ff00) >> 8), + ((SerialNumber[1] & 0x000000ff) >> 0), + ((SerialNumber[2] & 0xff000000) >> 24), + ((SerialNumber[2] & 0x00ff0000) >> 16), + ((SerialNumber[2] & 0x0000ff00) >> 8), + ((SerialNumber[2] & 0x000000ff) >> 0), + ((SerialNumber[3] & 0xff000000) >> 24), + ((SerialNumber[3] & 0x00ff0000) >> 16), + ((SerialNumber[3] & 0x0000ff00) >> 8), + ((SerialNumber[3] & 0x000000ff) >> 0)); + this->ChipID.SerialNumber = sn; + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUPowerManagement() +{ + // Check to see if what we are about to do is supported... + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000007))) { + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false; + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false; + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false; + return false; + } + +#if USE_CPUID + int localCPUPowerManagement[4] = { 0, 0, 0, 0 }; + + if (!call_cpuid(0x80000007, localCPUPowerManagement)) { + return false; + } + + // Check for the power management capabilities of the CPU. + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = + ((localCPUPowerManagement[3] & 0x00000001) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = + ((localCPUPowerManagement[3] & 0x00000002) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = + ((localCPUPowerManagement[3] & 0x00000004) != 0); + + return true; + +#else + return false; +#endif +} + +#if USE_CPUID +// Used only in USE_CPUID implementation below. +static void SystemInformationStripLeadingSpace(std::string& str) +{ + // Because some manufacturers have leading white space - we have to + // post-process the name. + std::string::size_type pos = str.find_first_not_of(" "); + if (pos != std::string::npos) { + str.erase(0, pos); + } +} +#endif + +/** */ +bool SystemInformationImplementation::RetrieveExtendedCPUIdentity() +{ + // Check to see if what we are about to do is supported... + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000002))) + return false; + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000003))) + return false; + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000004))) + return false; + +#if USE_CPUID + int CPUExtendedIdentity[12]; + + if (!call_cpuid(0x80000002, CPUExtendedIdentity)) { + return false; + } + if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4)) { + return false; + } + if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8)) { + return false; + } + + // Process the returned information. + char nbuf[49]; + memcpy(&(nbuf[0]), &(CPUExtendedIdentity[0]), sizeof(int)); + memcpy(&(nbuf[4]), &(CPUExtendedIdentity[1]), sizeof(int)); + memcpy(&(nbuf[8]), &(CPUExtendedIdentity[2]), sizeof(int)); + memcpy(&(nbuf[12]), &(CPUExtendedIdentity[3]), sizeof(int)); + memcpy(&(nbuf[16]), &(CPUExtendedIdentity[4]), sizeof(int)); + memcpy(&(nbuf[20]), &(CPUExtendedIdentity[5]), sizeof(int)); + memcpy(&(nbuf[24]), &(CPUExtendedIdentity[6]), sizeof(int)); + memcpy(&(nbuf[28]), &(CPUExtendedIdentity[7]), sizeof(int)); + memcpy(&(nbuf[32]), &(CPUExtendedIdentity[8]), sizeof(int)); + memcpy(&(nbuf[36]), &(CPUExtendedIdentity[9]), sizeof(int)); + memcpy(&(nbuf[40]), &(CPUExtendedIdentity[10]), sizeof(int)); + memcpy(&(nbuf[44]), &(CPUExtendedIdentity[11]), sizeof(int)); + nbuf[48] = '\0'; + this->ChipID.ProcessorName = nbuf; + this->ChipID.ModelName = nbuf; + + // Because some manufacturers have leading white space - we have to + // post-process the name. + SystemInformationStripLeadingSpace(this->ChipID.ProcessorName); + return true; +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveClassicalCPUIdentity() +{ + // Start by decided which manufacturer we are using.... + switch (this->ChipManufacturer) { + case Intel: + // Check the family / model / revision to determine the CPU ID. + switch (this->ChipID.Family) { + case 3: + this->ChipID.ProcessorName = "Newer i80386 family"; + break; + case 4: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "i80486DX-25/33"; + break; + case 1: + this->ChipID.ProcessorName = "i80486DX-50"; + break; + case 2: + this->ChipID.ProcessorName = "i80486SX"; + break; + case 3: + this->ChipID.ProcessorName = "i80486DX2"; + break; + case 4: + this->ChipID.ProcessorName = "i80486SL"; + break; + case 5: + this->ChipID.ProcessorName = "i80486SX2"; + break; + case 7: + this->ChipID.ProcessorName = "i80486DX2 WriteBack"; + break; + case 8: + this->ChipID.ProcessorName = "i80486DX4"; + break; + case 9: + this->ChipID.ProcessorName = "i80486DX4 WriteBack"; + break; + default: + this->ChipID.ProcessorName = "Unknown 80486 family"; + return false; + } + break; + case 5: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "P5 A-Step"; + break; + case 1: + this->ChipID.ProcessorName = "P5"; + break; + case 2: + this->ChipID.ProcessorName = "P54C"; + break; + case 3: + this->ChipID.ProcessorName = "P24T OverDrive"; + break; + case 4: + this->ChipID.ProcessorName = "P55C"; + break; + case 7: + this->ChipID.ProcessorName = "P54C"; + break; + case 8: + this->ChipID.ProcessorName = "P55C (0.25micron)"; + break; + default: + this->ChipID.ProcessorName = "Unknown Pentium family"; + return false; + } + break; + case 6: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "P6 A-Step"; + break; + case 1: + this->ChipID.ProcessorName = "P6"; + break; + case 3: + this->ChipID.ProcessorName = "Pentium II (0.28 micron)"; + break; + case 5: + this->ChipID.ProcessorName = "Pentium II (0.25 micron)"; + break; + case 6: + this->ChipID.ProcessorName = "Pentium II With On-Die L2 Cache"; + break; + case 7: + this->ChipID.ProcessorName = "Pentium III (0.25 micron)"; + break; + case 8: + this->ChipID.ProcessorName = + "Pentium III (0.18 micron) With 256 KB On-Die L2 Cache "; + break; + case 0xa: + this->ChipID.ProcessorName = + "Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache "; + break; + case 0xb: + this->ChipID.ProcessorName = "Pentium III (0.13 micron) With " + "256 Or 512 KB On-Die L2 Cache "; + break; + case 23: + this->ChipID.ProcessorName = + "Intel(R) Core(TM)2 Duo CPU T9500 @ 2.60GHz"; + break; + default: + this->ChipID.ProcessorName = "Unknown P6 family"; + return false; + } + break; + case 7: + this->ChipID.ProcessorName = "Intel Merced (IA-64)"; + break; + case 0xf: + // Check the extended family bits... + switch (this->ChipID.ExtendedFamily) { + case 0: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; + break; + case 1: + this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; + break; + case 2: + this->ChipID.ProcessorName = "Pentium IV (0.13 micron)"; + break; + default: + this->ChipID.ProcessorName = "Unknown Pentium 4 family"; + return false; + } + break; + case 1: + this->ChipID.ProcessorName = "Intel McKinley (IA-64)"; + break; + default: + this->ChipID.ProcessorName = "Pentium"; + } + break; + default: + this->ChipID.ProcessorName = "Unknown Intel family"; + return false; + } + break; + + case AMD: + // Check the family / model / revision to determine the CPU ID. + switch (this->ChipID.Family) { + case 4: + switch (this->ChipID.Model) { + case 3: + this->ChipID.ProcessorName = "80486DX2"; + break; + case 7: + this->ChipID.ProcessorName = "80486DX2 WriteBack"; + break; + case 8: + this->ChipID.ProcessorName = "80486DX4"; + break; + case 9: + this->ChipID.ProcessorName = "80486DX4 WriteBack"; + break; + case 0xe: + this->ChipID.ProcessorName = "5x86"; + break; + case 0xf: + this->ChipID.ProcessorName = "5x86WB"; + break; + default: + this->ChipID.ProcessorName = "Unknown 80486 family"; + return false; + } + break; + case 5: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "SSA5 (PR75, PR90 = PR100)"; + break; + case 1: + this->ChipID.ProcessorName = "5k86 (PR120 = PR133)"; + break; + case 2: + this->ChipID.ProcessorName = "5k86 (PR166)"; + break; + case 3: + this->ChipID.ProcessorName = "5k86 (PR200)"; + break; + case 6: + this->ChipID.ProcessorName = "K6 (0.30 micron)"; + break; + case 7: + this->ChipID.ProcessorName = "K6 (0.25 micron)"; + break; + case 8: + this->ChipID.ProcessorName = "K6-2"; + break; + case 9: + this->ChipID.ProcessorName = "K6-III"; + break; + case 0xd: + this->ChipID.ProcessorName = "K6-2+ or K6-III+ (0.18 micron)"; + break; + default: + this->ChipID.ProcessorName = "Unknown 80586 family"; + return false; + } + break; + case 6: + switch (this->ChipID.Model) { + case 1: + this->ChipID.ProcessorName = "Athlon- (0.25 micron)"; + break; + case 2: + this->ChipID.ProcessorName = "Athlon- (0.18 micron)"; + break; + case 3: + this->ChipID.ProcessorName = "Duron- (SF core)"; + break; + case 4: + this->ChipID.ProcessorName = "Athlon- (Thunderbird core)"; + break; + case 6: + this->ChipID.ProcessorName = "Athlon- (Palomino core)"; + break; + case 7: + this->ChipID.ProcessorName = "Duron- (Morgan core)"; + break; + case 8: + if (this->Features.ExtendedFeatures.SupportsMP) + this->ChipID.ProcessorName = "Athlon - MP (Thoroughbred core)"; + else + this->ChipID.ProcessorName = "Athlon - XP (Thoroughbred core)"; + break; + default: + this->ChipID.ProcessorName = "Unknown K7 family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown AMD family"; + return false; + } + break; + + case Hygon: + this->ChipID.ProcessorName = "Unknown Hygon family"; + return false; + + case Transmeta: + switch (this->ChipID.Family) { + case 5: + switch (this->ChipID.Model) { + case 4: + this->ChipID.ProcessorName = "Crusoe TM3x00 and TM5x00"; + break; + default: + this->ChipID.ProcessorName = "Unknown Crusoe family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown Transmeta family"; + return false; + } + break; + + case Rise: + switch (this->ChipID.Family) { + case 5: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "mP6 (0.25 micron)"; + break; + case 2: + this->ChipID.ProcessorName = "mP6 (0.18 micron)"; + break; + default: + this->ChipID.ProcessorName = "Unknown Rise family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown Rise family"; + return false; + } + break; + + case UMC: + switch (this->ChipID.Family) { + case 4: + switch (this->ChipID.Model) { + case 1: + this->ChipID.ProcessorName = "U5D"; + break; + case 2: + this->ChipID.ProcessorName = "U5S"; + break; + default: + this->ChipID.ProcessorName = "Unknown UMC family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown UMC family"; + return false; + } + break; + + case IDT: + switch (this->ChipID.Family) { + case 5: + switch (this->ChipID.Model) { + case 4: + this->ChipID.ProcessorName = "C6"; + break; + case 8: + this->ChipID.ProcessorName = "C2"; + break; + case 9: + this->ChipID.ProcessorName = "C3"; + break; + default: + this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + return false; + } + break; + case 6: + switch (this->ChipID.Model) { + case 6: + this->ChipID.ProcessorName = "VIA Cyrix III - Samuel"; + break; + default: + this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + return false; + } + break; + + case Cyrix: + switch (this->ChipID.Family) { + case 4: + switch (this->ChipID.Model) { + case 4: + this->ChipID.ProcessorName = "MediaGX GX = GXm"; + break; + case 9: + this->ChipID.ProcessorName = "5x86"; + break; + default: + this->ChipID.ProcessorName = "Unknown Cx5x86 family"; + return false; + } + break; + case 5: + switch (this->ChipID.Model) { + case 2: + this->ChipID.ProcessorName = "Cx6x86"; + break; + case 4: + this->ChipID.ProcessorName = "MediaGX GXm"; + break; + default: + this->ChipID.ProcessorName = "Unknown Cx6x86 family"; + return false; + } + break; + case 6: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "6x86MX"; + break; + case 5: + this->ChipID.ProcessorName = "Cyrix M2 Core"; + break; + case 6: + this->ChipID.ProcessorName = "WinChip C5A Core"; + break; + case 7: + this->ChipID.ProcessorName = "WinChip C5B\\C5C Core"; + break; + case 8: + this->ChipID.ProcessorName = "WinChip C5C-T Core"; + break; + default: + this->ChipID.ProcessorName = "Unknown 6x86MX\\Cyrix III family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown Cyrix family"; + return false; + } + break; + + case NexGen: + switch (this->ChipID.Family) { + case 5: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "Nx586 or Nx586FPU"; + break; + default: + this->ChipID.ProcessorName = "Unknown NexGen family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown NexGen family"; + return false; + } + break; + + case NSC: + this->ChipID.ProcessorName = "Cx486SLC \\ DLC \\ Cx486S A-Step"; + break; + + case Sun: + case IBM: + case Motorola: + case HP: + case UnknownManufacturer: + default: + this->ChipID.ProcessorName = + "Unknown family"; // We cannot identify the processor. + return false; + } + + return true; +} + +/** Extract a value from the CPUInfo file */ +std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile( + std::string buffer, const char* word, size_t init) +{ + size_t pos = buffer.find(word, init); + if (pos != std::string::npos) { + this->CurrentPositionInFile = pos; + pos = buffer.find(':', pos); + size_t pos2 = buffer.find('\n', pos); + if (pos != std::string::npos && pos2 != std::string::npos) { + // It may happen that the beginning matches, but this is still not the + // requested key. + // An example is looking for "cpu" when "cpu family" comes first. So we + // check that + // we have only spaces from here to pos, otherwise we search again. + for (size_t i = this->CurrentPositionInFile + strlen(word); i < pos; + ++i) { + if (buffer[i] != ' ' && buffer[i] != '\t') { + return this->ExtractValueFromCpuInfoFile(buffer, word, pos2); + } + } + buffer.erase(0, pos + 2); + buffer.resize(pos2 - pos - 2); + return buffer; + } + } + this->CurrentPositionInFile = std::string::npos; + return ""; +} + +/** Query for the cpu status */ +bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() +{ + this->NumberOfLogicalCPU = 0; + this->NumberOfPhysicalCPU = 0; + std::string buffer; + + FILE* fd = fopen("/proc/cpuinfo", "r"); + if (!fd) { + std::cout << "Problem opening /proc/cpuinfo" << std::endl; + return false; + } + + size_t fileSize = 0; + while (!feof(fd)) { + buffer += static_cast(fgetc(fd)); + fileSize++; + } + fclose(fd); + buffer.resize(fileSize - 2); + // Number of logical CPUs (combination of multiple processors, multi-core + // and SMT) + size_t pos = buffer.find("processor\t"); + while (pos != std::string::npos) { + this->NumberOfLogicalCPU++; + pos = buffer.find("processor\t", pos + 1); + } + +#if defined(__linux) || defined(__CYGWIN__) + // Count sockets. + std::set PhysicalIDs; + std::string idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id"); + while (this->CurrentPositionInFile != std::string::npos) { + int id = atoi(idc.c_str()); + PhysicalIDs.insert(id); + idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id", + this->CurrentPositionInFile + 1); + } + uint64_t NumberOfSockets = PhysicalIDs.size(); + NumberOfSockets = std::max(NumberOfSockets, (uint64_t)1); + // Physical ids returned by Linux don't distinguish cores. + // We want to record the total number of cores in this->NumberOfPhysicalCPU + // (checking only the first proc) + std::string Cores = this->ExtractValueFromCpuInfoFile(buffer, "cpu cores"); + auto NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str()); + NumberOfCoresPerSocket = std::max(NumberOfCoresPerSocket, 1u); + this->NumberOfPhysicalCPU = + NumberOfCoresPerSocket * (unsigned int)NumberOfSockets; + +#else + // For systems which do not have "physical id" entries, neither "cpu cores" + // this has to be fixed for hyper-threading. + std::string cpucount = + this->ExtractValueFromCpuInfoFile(buffer, "cpu count"); + this->NumberOfPhysicalCPU = this->NumberOfLogicalCPU = + atoi(cpucount.c_str()); +#endif + // gotta have one, and if this is 0 then we get a / by 0n + // better to have a bad answer than a crash + if (this->NumberOfPhysicalCPU <= 0) { + this->NumberOfPhysicalCPU = 1; + } + // LogicalProcessorsPerPhysical>1 => SMT. + this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = + this->NumberOfLogicalCPU / this->NumberOfPhysicalCPU; + + // CPU speed (checking only the first processor) + std::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "cpu MHz"); + if (!CPUSpeed.empty()) { + this->CPUSpeedInMHz = static_cast(atof(CPUSpeed.c_str())); + } +#ifdef __linux + else { + // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal + CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "Cpu0ClkTck"); + this->CPUSpeedInMHz = + static_cast(strtoull(CPUSpeed.c_str(), nullptr, 16)) / 1000000.0f; + } +#endif + + // Chip family + std::string familyStr = + this->ExtractValueFromCpuInfoFile(buffer, "cpu family"); + if (familyStr.empty()) { + familyStr = this->ExtractValueFromCpuInfoFile(buffer, "CPU architecture"); + } + this->ChipID.Family = atoi(familyStr.c_str()); + + // Chip Vendor + this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer, "vendor_id"); + this->FindManufacturer(familyStr); + + // second try for setting family + if (this->ChipID.Family == 0 && this->ChipManufacturer == HP) { + if (familyStr == "PA-RISC 1.1a") + this->ChipID.Family = 0x11a; + else if (familyStr == "PA-RISC 2.0") + this->ChipID.Family = 0x200; + // If you really get CMake to work on a machine not belonging to + // any of those families I owe you a dinner if you get it to + // contribute nightly builds regularly. + } + + // Chip Model + this->ChipID.Model = + atoi(this->ExtractValueFromCpuInfoFile(buffer, "model").c_str()); + if (!this->RetrieveClassicalCPUIdentity()) { + // Some platforms (e.g. PA-RISC) tell us their CPU name here. + // Note: x86 does not. + std::string cpuname = this->ExtractValueFromCpuInfoFile(buffer, "cpu"); + if (!cpuname.empty()) { + this->ChipID.ProcessorName = cpuname; + } + } + + // Chip revision + std::string cpurev = this->ExtractValueFromCpuInfoFile(buffer, "stepping"); + if (cpurev.empty()) { + cpurev = this->ExtractValueFromCpuInfoFile(buffer, "CPU revision"); + } + this->ChipID.Revision = atoi(cpurev.c_str()); + + // Chip Model Name + this->ChipID.ModelName = + this->ExtractValueFromCpuInfoFile(buffer, "model name"); + + // L1 Cache size + // Different architectures may show different names for the caches. + // Sum up everything we find. + std::vector cachename; + cachename.clear(); + + cachename.push_back("cache size"); // e.g. x86 + cachename.push_back("I-cache"); // e.g. PA-RISC + cachename.push_back("D-cache"); // e.g. PA-RISC + + this->Features.L1CacheSize = 0; + for (auto& index : cachename) { + std::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer, index); + if (!cacheSize.empty()) { + pos = cacheSize.find(" KB"); + if (pos != std::string::npos) { + cacheSize.resize(pos); + } + this->Features.L1CacheSize += atoi(cacheSize.c_str()); + } + } + + // processor feature flags (probably x86 specific) + std::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer, "flags"); + if (!cpurev.empty()) { + // now we can match every flags as space + flag + space + cpuflags = " " + cpuflags + " "; + if ((cpuflags.find(" fpu ") != std::string::npos)) { + this->Features.HasFPU = true; + } + if ((cpuflags.find(" tsc ") != std::string::npos)) { + this->Features.HasTSC = true; + } + if ((cpuflags.find(" mmx ") != std::string::npos)) { + this->Features.HasMMX = true; + } + if ((cpuflags.find(" sse ") != std::string::npos)) { + this->Features.HasSSE = true; + } + if ((cpuflags.find(" sse2 ") != std::string::npos)) { + this->Features.HasSSE2 = true; + } + if ((cpuflags.find(" apic ") != std::string::npos)) { + this->Features.HasAPIC = true; + } + if ((cpuflags.find(" cmov ") != std::string::npos)) { + this->Features.HasCMOV = true; + } + if ((cpuflags.find(" mtrr ") != std::string::npos)) { + this->Features.HasMTRR = true; + } + if ((cpuflags.find(" acpi ") != std::string::npos)) { + this->Features.HasACPI = true; + } + if ((cpuflags.find(" 3dnow ") != std::string::npos)) { + this->Features.ExtendedFeatures.Has3DNow = true; + } + } + + return true; +} + +bool SystemInformationImplementation::QueryProcessorBySysconf() +{ +#if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN) +// IRIX names this slightly different +# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN +#endif + +#ifdef _SC_NPROCESSORS_ONLN + long c = sysconf(_SC_NPROCESSORS_ONLN); + if (c <= 0) { + return false; + } + + this->NumberOfPhysicalCPU = static_cast(c); + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryProcessor() +{ + return this->QueryProcessorBySysconf(); +} + +/** +Get total system RAM in units of KiB. +*/ +long long SystemInformationImplementation::GetHostMemoryTotal() +{ +#if defined(_WIN32) +# if defined(_MSC_VER) && _MSC_VER < 1300 + MEMORYSTATUS stat; + stat.dwLength = sizeof(stat); + GlobalMemoryStatus(&stat); + return stat.dwTotalPhys / 1024; +# else + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + return statex.ullTotalPhys / 1024; +# endif +#elif defined(__linux) || defined(__CYGWIN__) + long long memTotal = 0; + int ierr = GetFieldFromFile("/proc/meminfo", "MemTotal:", memTotal); + if (ierr) { + return -1; + } + return memTotal; +#elif defined(__APPLE__) + uint64_t mem; + size_t len = sizeof(mem); + int ierr = sysctlbyname("hw.memsize", &mem, &len, nullptr, 0); + if (ierr) { + return -1; + } + return mem / 1024; +#else + return 0; +#endif +} + +/** +Get total system RAM in units of KiB. This may differ from the +host total if a host-wide resource limit is applied. +*/ +long long SystemInformationImplementation::GetHostMemoryAvailable( + const char* hostLimitEnvVarName) +{ + long long memTotal = this->GetHostMemoryTotal(); + + // the following mechanism is provided for systems that + // apply resource limits across groups of processes. + // this is of use on certain SMP systems (eg. SGI UV) + // where the host has a large amount of ram but a given user's + // access to it is severely restricted. The system will + // apply a limit across a set of processes. Units are in KiB. + if (hostLimitEnvVarName) { + const char* hostLimitEnvVarValue = getenv(hostLimitEnvVarName); + if (hostLimitEnvVarValue) { + long long hostLimit = std::atoll(hostLimitEnvVarValue); + if (hostLimit > 0) { + memTotal = min(hostLimit, memTotal); + } + } + } + + return memTotal; +} + +/** +Get total system RAM in units of KiB. This may differ from the +host total if a per-process resource limit is applied. +*/ +long long SystemInformationImplementation::GetProcMemoryAvailable( + const char* hostLimitEnvVarName, const char* procLimitEnvVarName) +{ + long long memAvail = this->GetHostMemoryAvailable(hostLimitEnvVarName); + + // the following mechanism is provide for systems where rlimits + // are not employed. Units are in KiB. + if (procLimitEnvVarName) { + const char* procLimitEnvVarValue = getenv(procLimitEnvVarName); + if (procLimitEnvVarValue) { + long long procLimit = std::atoll(procLimitEnvVarValue); + if (procLimit > 0) { + memAvail = min(procLimit, memAvail); + } + } + } + +#if defined(__linux) + int ierr; + ResourceLimitType rlim; + ierr = GetResourceLimit(RLIMIT_DATA, &rlim); + if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { + memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); + } + + ierr = GetResourceLimit(RLIMIT_AS, &rlim); + if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { + memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); + } +#elif defined(__APPLE__) + struct rlimit rlim; + int ierr; + ierr = getrlimit(RLIMIT_DATA, &rlim); + if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { + memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); + } + + ierr = getrlimit(RLIMIT_RSS, &rlim); + if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { + memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); + } +#endif + + return memAvail; +} + +/** +Get RAM used by all processes in the host, in units of KiB. +*/ +long long SystemInformationImplementation::GetHostMemoryUsed() +{ +#if defined(_WIN32) +# if defined(_MSC_VER) && _MSC_VER < 1300 + MEMORYSTATUS stat; + stat.dwLength = sizeof(stat); + GlobalMemoryStatus(&stat); + return (stat.dwTotalPhys - stat.dwAvailPhys) / 1024; +# else + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + return (statex.ullTotalPhys - statex.ullAvailPhys) / 1024; +# endif +#elif defined(__CYGWIN__) + const char* names[3] = { "MemTotal:", "MemFree:", nullptr }; + long long values[2] = { 0 }; + int ierr = GetFieldsFromFile("/proc/meminfo", names, values); + if (ierr) { + return ierr; + } + long long& memTotal = values[0]; + long long& memFree = values[1]; + return memTotal - memFree; +#elif defined(__linux) + // First try to use MemAvailable, but it only works on newer kernels + const char* names2[3] = { "MemTotal:", "MemAvailable:", nullptr }; + long long values2[2] = { 0 }; + int ierr = GetFieldsFromFile("/proc/meminfo", names2, values2); + if (ierr) { + const char* names4[5] = { "MemTotal:", "MemFree:", "Buffers:", "Cached:", + nullptr }; + long long values4[4] = { 0 }; + ierr = GetFieldsFromFile("/proc/meminfo", names4, values4); + if (ierr) { + return ierr; + } + long long& memTotal = values4[0]; + long long& memFree = values4[1]; + long long& memBuffers = values4[2]; + long long& memCached = values4[3]; + return memTotal - memFree - memBuffers - memCached; + } + long long& memTotal = values2[0]; + long long& memAvail = values2[1]; + return memTotal - memAvail; +#elif defined(__APPLE__) + long long psz = getpagesize(); + if (psz < 1) { + return -1; + } + const char* names[3] = { "Pages wired down:", "Pages active:", nullptr }; + long long values[2] = { 0 }; + int ierr = GetFieldsFromCommand("vm_stat", names, values); + if (ierr) { + return -1; + } + long long& vmWired = values[0]; + long long& vmActive = values[1]; + return ((vmActive + vmWired) * psz) / 1024; +#else + return 0; +#endif +} + +/** +Get system RAM used by the process associated with the given +process id in units of KiB. +*/ +long long SystemInformationImplementation::GetProcMemoryUsed() +{ +#if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI) + long pid = GetCurrentProcessId(); + HANDLE hProc; + hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); + if (hProc == 0) { + return -1; + } + PROCESS_MEMORY_COUNTERS pmc; + int ok = GetProcessMemoryInfo(hProc, &pmc, sizeof(pmc)); + CloseHandle(hProc); + if (!ok) { + return -2; + } + return pmc.WorkingSetSize / 1024; +#elif defined(__linux) || defined(__CYGWIN__) + long long memUsed = 0; + int ierr = GetFieldFromFile("/proc/self/status", "VmRSS:", memUsed); + if (ierr) { + return -1; + } + return memUsed; +#elif defined(__APPLE__) + long long memUsed = 0; + pid_t pid = getpid(); + std::ostringstream oss; + oss << "ps -o rss= -p " << pid; + FILE* file = popen(oss.str().c_str(), "r"); + if (file == nullptr) { + return -1; + } + oss.str(""); + while (!feof(file) && !ferror(file)) { + char buf[256] = { '\0' }; + errno = 0; + size_t nRead = fread(buf, 1, 256, file); + if (ferror(file) && (errno == EINTR)) { + clearerr(file); + } + if (nRead) + oss << buf; + } + int ierr = ferror(file); + pclose(file); + if (ierr) { + return -2; + } + std::istringstream iss(oss.str()); + iss >> memUsed; + return memUsed; +#else + return 0; +#endif +} + +double SystemInformationImplementation::GetLoadAverage() +{ +#if defined(KWSYS_CXX_HAS_GETLOADAVG) + double loadavg[3] = { 0.0, 0.0, 0.0 }; + if (getloadavg(loadavg, 3) > 0) { + return loadavg[0]; + } + return -0.0; +#elif defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes) + // Old windows.h headers do not provide GetSystemTimes. + typedef BOOL(WINAPI * GetSystemTimesType)(LPFILETIME, LPFILETIME, + LPFILETIME); + static GetSystemTimesType pGetSystemTimes = + (GetSystemTimesType)GetProcAddress(GetModuleHandleW(L"kernel32"), + "GetSystemTimes"); + FILETIME idleTime, kernelTime, userTime; + if (pGetSystemTimes && pGetSystemTimes(&idleTime, &kernelTime, &userTime)) { + unsigned __int64 const idleTicks = fileTimeToUInt64(idleTime); + unsigned __int64 const totalTicks = + fileTimeToUInt64(kernelTime) + fileTimeToUInt64(userTime); + return calculateCPULoad(idleTicks, totalTicks) * GetNumberOfPhysicalCPU(); + } + return -0.0; +#else + // Not implemented on this platform. + return -0.0; +#endif +} + +/** +Get the process id of the running process. +*/ +long long SystemInformationImplementation::GetProcessId() +{ +#if defined(_WIN32) + return GetCurrentProcessId(); +#elif defined(__linux) || defined(__APPLE__) || defined(__OpenBSD__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__CYGWIN__) + return getpid(); +#else + return -1; +#endif +} + +/** + * Used in GetProgramStack(...) below + */ +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && defined(_MSC_VER) && \ + _MSC_VER >= 1800 +# define KWSYS_SYSTEMINFORMATION_HAS_DBGHELP +# define TRACE_MAX_STACK_FRAMES 1024 +# define TRACE_MAX_FUNCTION_NAME_LENGTH 1024 +# pragma warning(push) +# pragma warning(disable : 4091) /* 'typedef ': ignored on left of '' */ +# include "dbghelp.h" +# pragma warning(pop) +#endif + +/** +return current program stack in a string +demangle cxx symbols if possible. +*/ +std::string SystemInformationImplementation::GetProgramStack(int firstFrame, + int wholePath) +{ + std::ostringstream oss; + std::string programStack; + +#ifdef KWSYS_SYSTEMINFORMATION_HAS_DBGHELP + (void)wholePath; + + void* stack[TRACE_MAX_STACK_FRAMES]; + HANDLE process = GetCurrentProcess(); + SymInitialize(process, nullptr, TRUE); + WORD numberOfFrames = + CaptureStackBackTrace(firstFrame, TRACE_MAX_STACK_FRAMES, stack, nullptr); + SYMBOL_INFO* symbol = static_cast( + malloc(sizeof(SYMBOL_INFO) + + (TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR))); + symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + DWORD displacement; + IMAGEHLP_LINE64 line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + for (int i = 0; i < numberOfFrames; i++) { + DWORD64 address = reinterpret_cast(stack[i]); + SymFromAddr(process, address, nullptr, symbol); + if (SymGetLineFromAddr64(process, address, &displacement, &line)) { + oss << " at " << symbol->Name << " in " << line.FileName << " line " + << line.LineNumber << std::endl; + } else { + oss << " at " << symbol->Name << std::endl; + } + } + free(symbol); + +#else + programStack += "" +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + "WARNING: The stack could not be examined " + "because backtrace is not supported.\n" +# elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD) + "WARNING: The stack trace will not use advanced " + "capabilities because this is a release build.\n" +# else +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + "WARNING: Function names will not be demangled " + "because dladdr is not available.\n" +# endif +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) + "WARNING: Function names will not be demangled " + "because cxxabi is not available.\n" +# endif +# endif + ; + +# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + void* stackSymbols[256]; + int nFrames = backtrace(stackSymbols, 256); + for (int i = firstFrame; i < nFrames; ++i) { + SymbolProperties symProps; + symProps.SetReportPath(wholePath); + symProps.Initialize(stackSymbols[i]); + oss << symProps << std::endl; + } +# else + (void)firstFrame; + (void)wholePath; +# endif +#endif + + programStack += oss.str(); + + return programStack; +} + +/** +when set print stack trace in response to common signals. +*/ +void SystemInformationImplementation::SetStackTraceOnError(int enable) +{ +#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) + static int saOrigValid = 0; + static struct sigaction saABRTOrig; + static struct sigaction saSEGVOrig; + static struct sigaction saTERMOrig; + static struct sigaction saINTOrig; + static struct sigaction saILLOrig; + static struct sigaction saBUSOrig; + static struct sigaction saFPEOrig; + + if (enable && !saOrigValid) { + // save the current actions + sigaction(SIGABRT, nullptr, &saABRTOrig); + sigaction(SIGSEGV, nullptr, &saSEGVOrig); + sigaction(SIGTERM, nullptr, &saTERMOrig); + sigaction(SIGINT, nullptr, &saINTOrig); + sigaction(SIGILL, nullptr, &saILLOrig); + sigaction(SIGBUS, nullptr, &saBUSOrig); + sigaction(SIGFPE, nullptr, &saFPEOrig); + + // enable read, disable write + saOrigValid = 1; + + // install ours + struct sigaction sa; + sa.sa_sigaction = (SigAction)StacktraceSignalHandler; + sa.sa_flags = SA_SIGINFO | SA_RESETHAND; +# ifdef SA_RESTART + sa.sa_flags |= SA_RESTART; +# endif + sigemptyset(&sa.sa_mask); + + sigaction(SIGABRT, &sa, nullptr); + sigaction(SIGSEGV, &sa, nullptr); + sigaction(SIGTERM, &sa, nullptr); + sigaction(SIGINT, &sa, nullptr); + sigaction(SIGILL, &sa, nullptr); + sigaction(SIGBUS, &sa, nullptr); + sigaction(SIGFPE, &sa, nullptr); + } else if (!enable && saOrigValid) { + // restore previous actions + sigaction(SIGABRT, &saABRTOrig, nullptr); + sigaction(SIGSEGV, &saSEGVOrig, nullptr); + sigaction(SIGTERM, &saTERMOrig, nullptr); + sigaction(SIGINT, &saINTOrig, nullptr); + sigaction(SIGILL, &saILLOrig, nullptr); + sigaction(SIGBUS, &saBUSOrig, nullptr); + sigaction(SIGFPE, &saFPEOrig, nullptr); + + // enable write, disable read + saOrigValid = 0; + } +#else + // avoid warning C4100 + (void)enable; +#endif +} + +bool SystemInformationImplementation::QueryWindowsMemory() +{ +#if defined(_WIN32) +# if defined(_MSC_VER) && _MSC_VER < 1300 + MEMORYSTATUS ms; + unsigned long tv, tp, av, ap; + ms.dwLength = sizeof(ms); + GlobalMemoryStatus(&ms); +# define MEM_VAL(value) dw##value +# else + MEMORYSTATUSEX ms; + DWORDLONG tv, tp, av, ap; + ms.dwLength = sizeof(ms); + if (0 == GlobalMemoryStatusEx(&ms)) { + return 0; + } +# define MEM_VAL(value) ull##value +# endif + tv = ms.MEM_VAL(TotalPageFile); + tp = ms.MEM_VAL(TotalPhys); + av = ms.MEM_VAL(AvailPageFile); + ap = ms.MEM_VAL(AvailPhys); + this->TotalVirtualMemory = tv >> 10 >> 10; + this->TotalPhysicalMemory = tp >> 10 >> 10; + this->AvailableVirtualMemory = av >> 10 >> 10; + this->AvailablePhysicalMemory = ap >> 10 >> 10; + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryLinuxMemory() +{ +#if defined(__linux) + unsigned long tv = 0; + unsigned long tp = 0; + unsigned long av = 0; + unsigned long ap = 0; + + char buffer[1024]; // for reading lines + + int linuxMajor = 0; + int linuxMinor = 0; + + // Find the Linux kernel version first + struct utsname unameInfo; + int errorFlag = uname(&unameInfo); + if (errorFlag != 0) { + std::cout << "Problem calling uname(): " << strerror(errno) << std::endl; + return false; + } + + if (strlen(unameInfo.release) >= 3) { + // release looks like "2.6.3-15mdk-i686-up-4GB" + char majorChar = unameInfo.release[0]; + char minorChar = unameInfo.release[2]; + + if (isdigit(majorChar)) { + linuxMajor = majorChar - '0'; + } + + if (isdigit(minorChar)) { + linuxMinor = minorChar - '0'; + } + } + + FILE* fd = fopen("/proc/meminfo", "r"); + if (!fd) { + std::cout << "Problem opening /proc/meminfo" << std::endl; + return false; + } + + if (linuxMajor >= 3 || ((linuxMajor >= 2) && (linuxMinor >= 6))) { + // new /proc/meminfo format since kernel 2.6.x + // Rigorously, this test should check from the developing version 2.5.x + // that introduced the new format... + + enum + { + mMemTotal, + mMemFree, + mBuffers, + mCached, + mSwapTotal, + mSwapFree + }; + const char* format[6] = { "MemTotal:%lu kB", "MemFree:%lu kB", + "Buffers:%lu kB", "Cached:%lu kB", + "SwapTotal:%lu kB", "SwapFree:%lu kB" }; + bool have[6] = { false, false, false, false, false, false }; + unsigned long value[6]; + int count = 0; + while (fgets(buffer, static_cast(sizeof(buffer)), fd)) { + for (int i = 0; i < 6; ++i) { + if (!have[i] && sscanf(buffer, format[i], &value[i]) == 1) { + have[i] = true; + ++count; + } + } + } + if (count == 6) { + this->TotalPhysicalMemory = value[mMemTotal] / 1024; + this->AvailablePhysicalMemory = + (value[mMemFree] + value[mBuffers] + value[mCached]) / 1024; + this->TotalVirtualMemory = value[mSwapTotal] / 1024; + this->AvailableVirtualMemory = value[mSwapFree] / 1024; + } else { + std::cout << "Problem parsing /proc/meminfo" << std::endl; + fclose(fd); + return false; + } + } else { + // /proc/meminfo format for kernel older than 2.6.x + + unsigned long temp; + unsigned long cachedMem; + unsigned long buffersMem; + // Skip "total: used:..." + char* r = fgets(buffer, static_cast(sizeof(buffer)), fd); + int status = 0; + if (r == buffer) { + status += fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n", &tp, &temp, &ap, + &temp, &buffersMem, &cachedMem); + } + if (status == 6) { + status += fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av); + } + if (status == 9) { + this->TotalVirtualMemory = tv >> 10 >> 10; + this->TotalPhysicalMemory = tp >> 10 >> 10; + this->AvailableVirtualMemory = av >> 10 >> 10; + this->AvailablePhysicalMemory = + (ap + buffersMem + cachedMem) >> 10 >> 10; + } else { + std::cout << "Problem parsing /proc/meminfo" << std::endl; + fclose(fd); + return false; + } + } + fclose(fd); + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryCygwinMemory() +{ +#ifdef __CYGWIN__ + // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin, + // see http://cygwin.com/ml/cygwin/2006-06/msg00350.html + // Therefore just use 4096 as the page size of Windows. + long m = sysconf(_SC_PHYS_PAGES); + if (m < 0) { + return false; + } + this->TotalPhysicalMemory = m >> 8; + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryAIXMemory() +{ +#if defined(_AIX) && defined(_SC_AIX_REALMEM) + long c = sysconf(_SC_AIX_REALMEM); + if (c <= 0) { + return false; + } + + this->TotalPhysicalMemory = c / 1024; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryMemoryBySysconf() +{ +#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) + // Assume the mmap() granularity as returned by _SC_PAGESIZE is also + // the system page size. The only known system where this isn't true + // is Cygwin. + long p = sysconf(_SC_PHYS_PAGES); + long m = sysconf(_SC_PAGESIZE); + + if (p < 0 || m < 0) { + return false; + } + + // assume pagesize is a power of 2 and smaller 1 MiB + size_t pagediv = (1024 * 1024 / m); + + this->TotalPhysicalMemory = p; + this->TotalPhysicalMemory /= pagediv; + +# if defined(_SC_AVPHYS_PAGES) + p = sysconf(_SC_AVPHYS_PAGES); + if (p < 0) { + return false; + } + + this->AvailablePhysicalMemory = p; + this->AvailablePhysicalMemory /= pagediv; +# endif + + return true; +#else + return false; +#endif +} + +/** Query for the memory status */ +bool SystemInformationImplementation::QueryMemory() +{ + return this->QueryMemoryBySysconf(); +} + +/** */ +size_t SystemInformationImplementation::GetTotalVirtualMemory() const +{ + return this->TotalVirtualMemory; +} + +/** */ +size_t SystemInformationImplementation::GetAvailableVirtualMemory() const +{ + return this->AvailableVirtualMemory; +} + +size_t SystemInformationImplementation::GetTotalPhysicalMemory() const +{ + return this->TotalPhysicalMemory; +} + +/** */ +size_t SystemInformationImplementation::GetAvailablePhysicalMemory() const +{ + return this->AvailablePhysicalMemory; +} + +/** Get Cycle differences */ +long long SystemInformationImplementation::GetCyclesDifference( + DELAY_FUNC DelayFunction, unsigned int uiParameter) +{ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + unsigned __int64 stamp1, stamp2; + +# ifdef _M_ARM64 + stamp1 = _ReadStatusReg(ARM64_PMCCNTR_EL0); + DelayFunction(uiParameter); + stamp2 = _ReadStatusReg(ARM64_PMCCNTR_EL0); +# else + stamp1 = __rdtsc(); + DelayFunction(uiParameter); + stamp2 = __rdtsc(); +# endif + + return stamp2 - stamp1; +#elif USE_ASM_INSTRUCTIONS + + unsigned int edx1, eax1; + unsigned int edx2, eax2; + + // Calculate the frequency of the CPU instructions. + __try { + _asm { + push uiParameter ; push parameter param + mov ebx, DelayFunction ; store func in ebx + + RDTSC_INSTRUCTION + + mov esi, eax ; esi = eax + mov edi, edx ; edi = edx + + call ebx ; call the delay functions + + RDTSC_INSTRUCTION + + pop ebx + + mov edx2, edx ; edx2 = edx + mov eax2, eax ; eax2 = eax + + mov edx1, edi ; edx2 = edi + mov eax1, esi ; eax2 = esi + } + } __except (1) { + return -1; + } + + return ((((__int64)edx2 << 32) + eax2) - (((__int64)edx1 << 32) + eax1)); + +#else + (void)DelayFunction; + (void)uiParameter; + return -1; +#endif +} + +/** Compute the delay overhead */ +void SystemInformationImplementation::DelayOverhead(unsigned int uiMS) +{ +#if defined(_WIN32) + LARGE_INTEGER Frequency, StartCounter, EndCounter; + __int64 x; + + // Get the frequency of the high performance counter. + if (!QueryPerformanceFrequency(&Frequency)) { + return; + } + x = Frequency.QuadPart / 1000 * uiMS; + + // Get the starting position of the counter. + QueryPerformanceCounter(&StartCounter); + + do { + // Get the ending position of the counter. + QueryPerformanceCounter(&EndCounter); + } while (EndCounter.QuadPart - StartCounter.QuadPart == x); +#endif + (void)uiMS; +} + +/** Works only for windows */ +bool SystemInformationImplementation::IsSMTSupported() const +{ + return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical > 1; +} + +/** Return the APIC Id. Works only for windows. */ +unsigned char SystemInformationImplementation::GetAPICId() +{ + int Regs[4] = { 0, 0, 0, 0 }; + +#if USE_CPUID + if (!this->IsSMTSupported()) { + return static_cast(-1); // HT not supported + } // Logical processor = 1 + call_cpuid(1, Regs); +#endif + + return static_cast((Regs[1] & INITIAL_APIC_ID_BITS) >> 24); +} + +/** Count the number of CPUs. Works only on windows. */ +void SystemInformationImplementation::CPUCountWindows() +{ +#if defined(_WIN32) + this->NumberOfPhysicalCPU = 0; + this->NumberOfLogicalCPU = 0; + + typedef BOOL(WINAPI * GetLogicalProcessorInformationType)( + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); + static GetLogicalProcessorInformationType pGetLogicalProcessorInformation = + (GetLogicalProcessorInformationType)GetProcAddress( + GetModuleHandleW(L"kernel32"), "GetLogicalProcessorInformation"); + + if (!pGetLogicalProcessorInformation) { + // Fallback to approximate implementation on ancient Windows versions. + SYSTEM_INFO info; + ZeroMemory(&info, sizeof(info)); + GetSystemInfo(&info); + this->NumberOfPhysicalCPU = + static_cast(info.dwNumberOfProcessors); + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + return; + } + + std::vector ProcInfo; + { + DWORD Length = 0; + DWORD rc = pGetLogicalProcessorInformation(nullptr, &Length); + assert(FALSE == rc); + (void)rc; // Silence unused variable warning + assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER); + ProcInfo.resize(Length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); + rc = pGetLogicalProcessorInformation(&ProcInfo[0], &Length); + assert(rc != FALSE); + (void)rc; // Silence unused variable warning + } + + typedef std::vector::iterator + pinfoIt_t; + for (pinfoIt_t it = ProcInfo.begin(); it != ProcInfo.end(); ++it) { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION PInfo = *it; + if (PInfo.Relationship != RelationProcessorCore) { + continue; + } + + std::bitset::digits> ProcMask( + (unsigned long long)PInfo.ProcessorMask); + unsigned int count = (unsigned int)ProcMask.count(); + if (count == 0) { // I think this should never happen, but just to be safe. + continue; + } + this->NumberOfPhysicalCPU++; + this->NumberOfLogicalCPU += (unsigned int)count; + this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = count; + } + this->NumberOfPhysicalCPU = std::max(1u, this->NumberOfPhysicalCPU); + this->NumberOfLogicalCPU = std::max(1u, this->NumberOfLogicalCPU); +#else +#endif +} + +/** Return the number of logical CPUs on the system */ +unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU() const +{ + return this->NumberOfLogicalCPU; +} + +/** Return the number of physical CPUs on the system */ +unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() const +{ + return this->NumberOfPhysicalCPU; +} + +/** For Mac use sysctlbyname calls to find system info */ +bool SystemInformationImplementation::ParseSysCtl() +{ +#if defined(__APPLE__) + char retBuf[128]; + int err = 0; + uint64_t value = 0; + size_t len = sizeof(value); + sysctlbyname("hw.memsize", &value, &len, nullptr, 0); + this->TotalPhysicalMemory = static_cast(value / 1048576); + + // Parse values for Mac + this->AvailablePhysicalMemory = 0; + vm_statistics_data_t vmstat; + mach_msg_type_number_t count = HOST_VM_INFO_COUNT; + if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, + &count) == KERN_SUCCESS) { + len = sizeof(value); + err = sysctlbyname("hw.pagesize", &value, &len, nullptr, 0); + int64_t available_memory = + (vmstat.free_count + vmstat.inactive_count) * value; + this->AvailablePhysicalMemory = + static_cast(available_memory / 1048576); + } + +# ifdef VM_SWAPUSAGE + // Virtual memory. + int mib[2] = { CTL_VM, VM_SWAPUSAGE }; + unsigned int miblen = + static_cast(sizeof(mib) / sizeof(mib[0])); + struct xsw_usage swap; + len = sizeof(swap); + err = sysctl(mib, miblen, &swap, &len, nullptr, 0); + if (err == 0) { + this->AvailableVirtualMemory = + static_cast(swap.xsu_avail / 1048576); + this->TotalVirtualMemory = static_cast(swap.xsu_total / 1048576); + } +# else + this->AvailableVirtualMemory = 0; + this->TotalVirtualMemory = 0; +# endif + + // CPU Info + len = sizeof(this->NumberOfPhysicalCPU); + sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, nullptr, 0); + len = sizeof(this->NumberOfLogicalCPU); + sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, nullptr, 0); + + int cores_per_package = 0; + len = sizeof(cores_per_package); + err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len, + nullptr, 0); + // That name was not found, default to 1 + this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = + err != 0 ? 1 : static_cast(cores_per_package); + + len = sizeof(value); + sysctlbyname("hw.cpufrequency", &value, &len, nullptr, 0); + this->CPUSpeedInMHz = static_cast(value) / 1000000; + + // Chip family + len = sizeof(this->ChipID.Family); + // Seems only the intel chips will have this name so if this fails it is + // probably a PPC machine + err = + sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, nullptr, 0); + if (err != 0) // Go back to names we know but are less descriptive + { + this->ChipID.Family = 0; + ::memset(retBuf, 0, 128); + len = 32; + err = sysctlbyname("hw.machine", &retBuf, &len, nullptr, 0); + std::string machineBuf(retBuf); + if (machineBuf.find_first_of("Power") != std::string::npos) { + this->ChipID.Vendor = "IBM"; + len = sizeof(this->ChipID.Family); + err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, nullptr, 0); + len = sizeof(this->ChipID.Model); + err = + sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, nullptr, 0); + this->FindManufacturer(); + } + } else // Should be an Intel Chip. + { + len = sizeof(this->ChipID.Family); + err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, + nullptr, 0); + + ::memset(retBuf, 0, 128); + len = 128; + err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, nullptr, 0); + // Chip Vendor + this->ChipID.Vendor = retBuf; + this->FindManufacturer(); + + // Chip Model + len = sizeof(value); + err = sysctlbyname("machdep.cpu.model", &value, &len, nullptr, 0); + this->ChipID.Model = static_cast(value); + + // Chip Stepping + len = sizeof(value); + value = 0; + err = sysctlbyname("machdep.cpu.stepping", &value, &len, nullptr, 0); + if (!err) { + this->ChipID.Revision = static_cast(value); + } + + // feature string + char* buf = nullptr; + size_t allocSize = 128; + + err = 0; + len = 0; + + // sysctlbyname() will return with err==0 && len==0 if the buffer is too + // small + while (err == 0 && len == 0) { + delete[] buf; + allocSize *= 2; + buf = new char[allocSize]; + if (!buf) { + break; + } + buf[0] = ' '; + len = allocSize - 2; // keep space for leading and trailing space + err = sysctlbyname("machdep.cpu.features", buf + 1, &len, nullptr, 0); + } + if (!err && buf && len) { + // now we can match every flags as space + flag + space + buf[len + 1] = ' '; + std::string cpuflags(buf, len + 2); + + if ((cpuflags.find(" FPU ") != std::string::npos)) { + this->Features.HasFPU = true; + } + if ((cpuflags.find(" TSC ") != std::string::npos)) { + this->Features.HasTSC = true; + } + if ((cpuflags.find(" MMX ") != std::string::npos)) { + this->Features.HasMMX = true; + } + if ((cpuflags.find(" SSE ") != std::string::npos)) { + this->Features.HasSSE = true; + } + if ((cpuflags.find(" SSE2 ") != std::string::npos)) { + this->Features.HasSSE2 = true; + } + if ((cpuflags.find(" APIC ") != std::string::npos)) { + this->Features.HasAPIC = true; + } + if ((cpuflags.find(" CMOV ") != std::string::npos)) { + this->Features.HasCMOV = true; + } + if ((cpuflags.find(" MTRR ") != std::string::npos)) { + this->Features.HasMTRR = true; + } + if ((cpuflags.find(" ACPI ") != std::string::npos)) { + this->Features.HasACPI = true; + } + } + delete[] buf; + } + + // brand string + ::memset(retBuf, 0, sizeof(retBuf)); + len = sizeof(retBuf); + err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, nullptr, 0); + if (!err) { + this->ChipID.ProcessorName = retBuf; + this->ChipID.ModelName = retBuf; + } + + // Cache size + len = sizeof(value); + err = sysctlbyname("hw.l1icachesize", &value, &len, nullptr, 0); + this->Features.L1CacheSize = static_cast(value); + len = sizeof(value); + err = sysctlbyname("hw.l2cachesize", &value, &len, nullptr, 0); + this->Features.L2CacheSize = static_cast(value); + + return true; +#else + return false; +#endif +} + +/** Extract a value from sysctl command */ +std::string SystemInformationImplementation::ExtractValueFromSysCtl( + const char* word) +{ + size_t pos = this->SysCtlBuffer.find(word); + if (pos != std::string::npos) { + pos = this->SysCtlBuffer.find(": ", pos); + size_t pos2 = this->SysCtlBuffer.find('\n', pos); + if (pos != std::string::npos && pos2 != std::string::npos) { + return this->SysCtlBuffer.substr(pos + 2, pos2 - pos - 2); + } + } + return ""; +} + +/** Run a given process */ +std::string SystemInformationImplementation::RunProcess( + std::vector args) +{ + std::string buffer; + + // Run the application + kwsysProcess* gp = kwsysProcess_New(); + kwsysProcess_SetCommand(gp, args.data()); + kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1); + + kwsysProcess_Execute(gp); + + char* data = nullptr; + int length; + double timeout = 255; + int pipe; // pipe id as returned by kwsysProcess_WaitForData() + + while ((static_cast( + pipe = kwsysProcess_WaitForData(gp, &data, &length, &timeout)), + (pipe == kwsysProcess_Pipe_STDOUT || + pipe == kwsysProcess_Pipe_STDERR))) // wait for 1s + { + buffer.append(data, length); + } + kwsysProcess_WaitForExit(gp, nullptr); + + int result = 0; + switch (kwsysProcess_GetState(gp)) { + case kwsysProcess_State_Exited: { + result = kwsysProcess_GetExitValue(gp); + } break; + case kwsysProcess_State_Error: { + std::cerr << "Error: Could not run " << args[0] << ":\n"; + std::cerr << kwsysProcess_GetErrorString(gp) << "\n"; + } break; + case kwsysProcess_State_Exception: { + std::cerr << "Error: " << args[0] << " terminated with an exception: " + << kwsysProcess_GetExceptionString(gp) << "\n"; + } break; + case kwsysProcess_State_Starting: + case kwsysProcess_State_Executing: + case kwsysProcess_State_Expired: + case kwsysProcess_State_Killed: { + // Should not get here. + std::cerr << "Unexpected ending state after running " << args[0] + << std::endl; + } break; + } + kwsysProcess_Delete(gp); + if (result) { + std::cerr << "Error " << args[0] << " returned :" << result << "\n"; + } + return buffer; +} + +std::string SystemInformationImplementation::ParseValueFromKStat( + const char* arguments) +{ + std::vector args_string; + std::string command = arguments; + size_t start = std::string::npos; + size_t pos = command.find(' ', 0); + while (pos != std::string::npos) { + bool inQuotes = false; + // Check if we are between quotes + size_t b0 = command.find('"', 0); + size_t b1 = command.find('"', b0 + 1); + while (b0 != std::string::npos && b1 != std::string::npos && b1 > b0) { + if (pos > b0 && pos < b1) { + inQuotes = true; + break; + } + b0 = command.find('"', b1 + 1); + b1 = command.find('"', b0 + 1); + } + + if (!inQuotes) { + args_string.push_back(command.substr(start + 1, pos - start - 1)); + std::string& arg = args_string.back(); + + // Remove the quotes if any + arg.erase(std::remove(arg.begin(), arg.end(), '"'), arg.end()); + start = pos; + } + pos = command.find(' ', pos + 1); + } + command.erase(0, start + 1); + args_string.push_back(command); + + std::vector args; + args.reserve(3 + args_string.size()); + args.push_back("kstat"); + args.push_back("-p"); + for (auto& i : args_string) { + args.push_back(i.c_str()); + } + args.push_back(nullptr); + + std::string buffer = this->RunProcess(args); + + std::string value; + for (size_t i = buffer.size() - 1; i > 0; i--) { + if (buffer[i] == ' ' || buffer[i] == '\t') { + break; + } + if (buffer[i] != '\n' && buffer[i] != '\r') { + value.insert(0u, 1, buffer[i]); + } + } + return value; +} + +/** Querying for system information from Solaris */ +bool SystemInformationImplementation::QuerySolarisMemory() +{ +#if defined(__SVR4) && defined(__sun) +// Solaris allows querying this value by sysconf, but if this is +// a 32 bit process on a 64 bit host the returned memory will be +// limited to 4GiB. So if this is a 32 bit process or if the sysconf +// method fails use the kstat interface. +# if SIZEOF_VOID_P == 8 + if (this->QueryMemoryBySysconf()) { + return true; + } +# endif + + char* tail; + unsigned long totalMemory = + strtoul(this->ParseValueFromKStat("-s physmem").c_str(), &tail, 0); + this->TotalPhysicalMemory = totalMemory / 128; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QuerySolarisProcessor() +{ + if (!this->QueryProcessorBySysconf()) { + return false; + } + + // Parse values + this->CPUSpeedInMHz = static_cast( + atoi(this->ParseValueFromKStat("-s clock_MHz").c_str())); + + // Chip family + this->ChipID.Family = 0; + + // Chip Model + this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type"); + this->ChipID.Model = 0; + + // Chip Vendor + if (this->ChipID.ProcessorName != "i386") { + this->ChipID.Vendor = "Sun"; + this->FindManufacturer(); + } + + return true; +} + +/** Querying for system information from Haiku OS */ +bool SystemInformationImplementation::QueryHaikuInfo() +{ +#if defined(__HAIKU__) + + // CPU count + system_info info; + get_system_info(&info); + this->NumberOfPhysicalCPU = info.cpu_count; + + // CPU speed + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = 0; + get_cpu_topology_info(0, &topologyNodeCount); + if (topologyNodeCount != 0) + topology = new cpu_topology_node_info[topologyNodeCount]; + get_cpu_topology_info(topology, &topologyNodeCount); + + for (uint32 i = 0; i < topologyNodeCount; i++) { + if (topology[i].type == B_TOPOLOGY_CORE) { + this->CPUSpeedInMHz = + topology[i].data.core.default_frequency / 1000000.0f; + break; + } + } + + delete[] topology; + + // Physical Memory + this->TotalPhysicalMemory = (info.max_pages * B_PAGE_SIZE) / (1024 * 1024); + this->AvailablePhysicalMemory = this->TotalPhysicalMemory - + ((info.used_pages * B_PAGE_SIZE) / (1024 * 1024)); + + // NOTE: get_system_info_etc is currently a private call so just set to 0 + // until it becomes public + this->TotalVirtualMemory = 0; + this->AvailableVirtualMemory = 0; + + // Retrieve cpuid_info union for cpu 0 + cpuid_info cpu_info; + get_cpuid(&cpu_info, 0, 0); + + // Chip Vendor + // Use a temporary buffer so that we can add NULL termination to the string + char vbuf[13]; + strncpy(vbuf, cpu_info.eax_0.vendor_id, 12); + vbuf[12] = '\0'; + this->ChipID.Vendor = vbuf; + + this->FindManufacturer(); + + // Retrieve cpuid_info union for cpu 0 this time using a register value of 1 + get_cpuid(&cpu_info, 1, 0); + + this->NumberOfLogicalCPU = cpu_info.eax_1.logical_cpus; + + // Chip type + this->ChipID.Type = cpu_info.eax_1.type; + + // Chip family + this->ChipID.Family = cpu_info.eax_1.family; + + // Chip Model + this->ChipID.Model = cpu_info.eax_1.model; + + // Chip Revision + this->ChipID.Revision = cpu_info.eax_1.stepping; + + // Chip Extended Family + this->ChipID.ExtendedFamily = cpu_info.eax_1.extended_family; + + // Chip Extended Model + this->ChipID.ExtendedModel = cpu_info.eax_1.extended_model; + + // Get ChipID.ProcessorName from other information already gathered + this->RetrieveClassicalCPUIdentity(); + + // Cache size + this->Features.L1CacheSize = 0; + this->Features.L2CacheSize = 0; + + return true; + +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryQNXMemory() +{ +#if defined(__QNX__) + std::string buffer; + std::vector args; + args.clear(); + + args.push_back("showmem"); + args.push_back("-S"); + args.push_back(0); + buffer = this->RunProcess(args); + args.clear(); + + size_t pos = buffer.find("System RAM:"); + if (pos == std::string::npos) + return false; + pos = buffer.find(":", pos); + size_t pos2 = buffer.find("M (", pos); + if (pos2 == std::string::npos) + return false; + + pos++; + while (buffer[pos] == ' ') + pos++; + + buffer.erase(0, pos); + buffer.resize(pos2); + this->TotalPhysicalMemory = atoi(buffer.c_str()); + return true; +#endif + return false; +} + +bool SystemInformationImplementation::QueryBSDMemory() +{ +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) + int ctrl[2] = { CTL_HW, HW_PHYSMEM }; +# if defined(HW_PHYSMEM64) + int64_t k; + ctrl[1] = HW_PHYSMEM64; +# else + int k; +# endif + size_t sz = sizeof(k); + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->TotalPhysicalMemory = k >> 10 >> 10; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryQNXProcessor() +{ +#if defined(__QNX__) + // the output on my QNX 6.4.1 looks like this: + // Processor1: 686 Pentium II Stepping 3 2175MHz FPU + std::string buffer; + std::vector args; + args.clear(); + + args.push_back("pidin"); + args.push_back("info"); + args.push_back(0); + buffer = this->RunProcess(args); + args.clear(); + + size_t pos = buffer.find("Processor1:"); + if (pos == std::string::npos) + return false; + + size_t pos2 = buffer.find("MHz", pos); + if (pos2 == std::string::npos) + return false; + + size_t pos3 = pos2; + while (buffer[pos3] != ' ') + --pos3; + + this->CPUSpeedInMHz = atoi(buffer.substr(pos3 + 1, pos2 - pos3 - 1).c_str()); + + pos2 = buffer.find(" Stepping", pos); + if (pos2 != std::string::npos) { + pos2 = buffer.find(" ", pos2 + 1); + if (pos2 != std::string::npos && pos2 < pos3) { + this->ChipID.Revision = + atoi(buffer.substr(pos2 + 1, pos3 - pos2).c_str()); + } + } + + this->NumberOfPhysicalCPU = 0; + do { + pos = buffer.find("\nProcessor", pos + 1); + ++this->NumberOfPhysicalCPU; + } while (pos != std::string::npos); + this->NumberOfLogicalCPU = 1; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryBSDProcessor() +{ +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) + int k; + size_t sz = sizeof(k); + int ctrl[2] = { CTL_HW, HW_NCPU }; + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->NumberOfPhysicalCPU = k; + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + +# if defined(HW_CPUSPEED) + ctrl[1] = HW_CPUSPEED; + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->CPUSpeedInMHz = (float)k; +# endif + +# if defined(CPU_SSE) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_SSE; + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->Features.HasSSE = (k > 0); +# endif + +# if defined(CPU_SSE2) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_SSE2; + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->Features.HasSSE2 = (k > 0); +# endif + +# if defined(CPU_CPUVENDOR) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_CPUVENDOR; + char vbuf[25]; + ::memset(vbuf, 0, sizeof(vbuf)); + sz = sizeof(vbuf) - 1; + if (sysctl(ctrl, 2, vbuf, &sz, nullptr, 0) != 0) { + return false; + } + + this->ChipID.Vendor = vbuf; + this->FindManufacturer(); +# endif + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryHPUXMemory() +{ +#if defined(__hpux) + unsigned long tv = 0; + unsigned long tp = 0; + unsigned long av = 0; + unsigned long ap = 0; + struct pst_static pst; + struct pst_dynamic pdy; + + unsigned long ps = 0; + if (pstat_getstatic(&pst, sizeof(pst), (size_t)1, 0) == -1) { + return false; + } + + ps = pst.page_size; + tp = pst.physical_memory * ps; + tv = (pst.physical_memory + pst.pst_maxmem) * ps; + if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t)1, 0) == -1) { + return false; + } + + ap = tp - pdy.psd_rm * ps; + av = tv - pdy.psd_vm; + this->TotalVirtualMemory = tv >> 10 >> 10; + this->TotalPhysicalMemory = tp >> 10 >> 10; + this->AvailableVirtualMemory = av >> 10 >> 10; + this->AvailablePhysicalMemory = ap >> 10 >> 10; + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryHPUXProcessor() +{ +#if defined(__hpux) +# if defined(KWSYS_SYS_HAS_MPCTL_H) + int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0); + if (c <= 0) { + return false; + } + + this->NumberOfPhysicalCPU = c; + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + + long t = sysconf(_SC_CPU_VERSION); + + if (t == -1) { + return false; + } + + switch (t) { + case CPU_PA_RISC1_0: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x100; + break; + case CPU_PA_RISC1_1: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x110; + break; + case CPU_PA_RISC2_0: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x200; + break; +# if defined(CPU_HP_INTEL_EM_1_0) || defined(CPU_IA64_ARCHREV_0) +# ifdef CPU_HP_INTEL_EM_1_0 + case CPU_HP_INTEL_EM_1_0: +# endif +# ifdef CPU_IA64_ARCHREV_0 + case CPU_IA64_ARCHREV_0: +# endif + this->ChipID.Vendor = "GenuineIntel"; + this->Features.HasIA64 = true; + break; +# endif + default: + return false; + } + + this->FindManufacturer(); + + return true; +# else + return false; +# endif +#else + return false; +#endif +} + +/** Query the operating system information */ +bool SystemInformationImplementation::QueryOSInformation() +{ +#if defined(_WIN32) + + this->OSName = "Windows"; + + OSVERSIONINFOEXW osvi; + BOOL bIsWindows64Bit; + BOOL bOsVersionInfoEx; + char operatingSystem[256]; + + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXW)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); +# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# pragma warning(push) +# ifdef __INTEL_COMPILER +# pragma warning(disable : 1478) +# elif defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +# else +# pragma warning(disable : 4996) +# endif +# endif + bOsVersionInfoEx = GetVersionExW((OSVERSIONINFOW*)&osvi); + if (!bOsVersionInfoEx) { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); + if (!GetVersionExW((OSVERSIONINFOW*)&osvi)) { + return false; + } + } +# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# ifdef __clang__ +# pragma clang diagnostic pop +# else +# pragma warning(pop) +# endif +# endif + + switch (osvi.dwPlatformId) { + case VER_PLATFORM_WIN32_NT: + // Test for the product. + if (osvi.dwMajorVersion <= 4) { + this->OSRelease = "NT"; + } + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { + this->OSRelease = "2000"; + } + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + this->OSRelease = "XP"; + } + // XP Professional x64 + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { + this->OSRelease = "XP"; + } +# ifdef VER_NT_WORKSTATION + // Test for product type. + if (bOsVersionInfoEx) { + if (osvi.wProductType == VER_NT_WORKSTATION) { + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) { + this->OSRelease = "Vista"; + } + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) { + this->OSRelease = "7"; + } +// VER_SUITE_PERSONAL may not be defined +# ifdef VER_SUITE_PERSONAL + else { + if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { + this->OSRelease += " Personal"; + } else { + this->OSRelease += " Professional"; + } + } +# endif + } else if (osvi.wProductType == VER_NT_SERVER) { + // Check for .NET Server instead of Windows XP. + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + this->OSRelease = ".NET"; + } + + // Continue with the type detection. + if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { + this->OSRelease += " DataCenter Server"; + } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { + this->OSRelease += " Advanced Server"; + } else { + this->OSRelease += " Server"; + } + } + + sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, + osvi.dwBuildNumber & 0xFFFF); + this->OSVersion = operatingSystem; + } else +# endif // VER_NT_WORKSTATION + { + HKEY hKey; + wchar_t szProductType[80]; + DWORD dwBufLen; + + // Query the registry to retrieve information. + RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, + KEY_QUERY_VALUE, &hKey); + RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr, + (LPBYTE)szProductType, &dwBufLen); + RegCloseKey(hKey); + + if (lstrcmpiW(L"WINNT", szProductType) == 0) { + this->OSRelease += " Professional"; + } + if (lstrcmpiW(L"LANMANNT", szProductType) == 0) { + // Decide between Windows 2000 Advanced Server and Windows .NET + // Enterprise Server. + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + this->OSRelease += " Standard Server"; + } else { + this->OSRelease += " Server"; + } + } + if (lstrcmpiW(L"SERVERNT", szProductType) == 0) { + // Decide between Windows 2000 Advanced Server and Windows .NET + // Enterprise Server. + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + this->OSRelease += " Enterprise Server"; + } else { + this->OSRelease += " Advanced Server"; + } + } + } + + // Display version, service pack (if any), and build number. + if (osvi.dwMajorVersion <= 4) { + // NB: NT 4.0 and earlier. + sprintf(operatingSystem, "version %ld.%ld %ls (Build %ld)", + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion, + osvi.dwBuildNumber & 0xFFFF); + this->OSVersion = operatingSystem; + } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + // Windows XP and .NET server. + typedef BOOL(CALLBACK * LPFNPROC)(HANDLE, BOOL*); + HINSTANCE hKernelDLL; + LPFNPROC DLLProc; + + // Load the Kernel32 DLL. + hKernelDLL = LoadLibraryW(L"kernel32"); + if (hKernelDLL != nullptr) { + // Only XP and .NET Server support IsWOW64Process so... Load + // dynamically! + DLLProc = (LPFNPROC)GetProcAddress(hKernelDLL, "IsWow64Process"); + + // If the function address is valid, call the function. + if (DLLProc != nullptr) + (DLLProc)(GetCurrentProcess(), &bIsWindows64Bit); + else + bIsWindows64Bit = false; + + // Free the DLL module. + FreeLibrary(hKernelDLL); + } + } else { + // Windows 2000 and everything else. + sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, + osvi.dwBuildNumber & 0xFFFF); + this->OSVersion = operatingSystem; + } + break; + + case VER_PLATFORM_WIN32_WINDOWS: + // Test for the product. + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { + this->OSRelease = "95"; + if (osvi.szCSDVersion[1] == 'C') { + this->OSRelease += "OSR 2.5"; + } else if (osvi.szCSDVersion[1] == 'B') { + this->OSRelease += "OSR 2"; + } + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { + this->OSRelease = "98"; + if (osvi.szCSDVersion[1] == 'A') { + this->OSRelease += "SE"; + } + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { + this->OSRelease = "Me"; + } + break; + + case VER_PLATFORM_WIN32s: + this->OSRelease = "Win32s"; + break; + + default: + this->OSRelease = "Unknown"; + break; + } + + // Get the hostname + WORD wVersionRequested; + WSADATA wsaData; + char name[255]; + wVersionRequested = MAKEWORD(2, 0); + + if (WSAStartup(wVersionRequested, &wsaData) == 0) { + gethostname(name, sizeof(name)); + WSACleanup(); + } + this->Hostname = name; + + const char* arch = getenv("PROCESSOR_ARCHITECTURE"); + const char* wow64 = getenv("PROCESSOR_ARCHITEW6432"); + if (arch) { + this->OSPlatform = arch; + } + + if (wow64) { + // the PROCESSOR_ARCHITEW6432 is only defined when running 32bit programs + // on 64bit OS + this->OSIs64Bit = true; + } else if (arch) { + // all values other than x86 map to 64bit architectures + this->OSIs64Bit = (strncmp(arch, "x86", 3) != 0); + } + +#else + + struct utsname unameInfo; + int errorFlag = uname(&unameInfo); + if (errorFlag == 0) { + this->OSName = unameInfo.sysname; + this->Hostname = unameInfo.nodename; + this->OSRelease = unameInfo.release; + this->OSVersion = unameInfo.version; + this->OSPlatform = unameInfo.machine; + + // This is still insufficient to capture 64bit architecture such + // powerpc and possible mips and sparc + if (this->OSPlatform.find_first_of("64") != std::string::npos) { + this->OSIs64Bit = true; + } + } + +# ifdef __APPLE__ + this->OSName = "Unknown Apple OS"; + this->OSRelease = "Unknown product version"; + this->OSVersion = "Unknown build version"; + + this->CallSwVers("-productName", this->OSName); + this->CallSwVers("-productVersion", this->OSRelease); + this->CallSwVers("-buildVersion", this->OSVersion); +# endif + +#endif + + return true; +} + +int SystemInformationImplementation::CallSwVers(const char* arg, + std::string& ver) +{ +#ifdef __APPLE__ + std::vector args; + args.push_back("sw_vers"); + args.push_back(arg); + args.push_back(nullptr); + ver = this->RunProcess(args); + this->TrimNewline(ver); +#else + // avoid C4100 + (void)arg; + (void)ver; +#endif + return 0; +} + +void SystemInformationImplementation::TrimNewline(std::string& output) +{ + // remove \r + std::string::size_type pos = 0; + while ((pos = output.find('\r', pos)) != std::string::npos) { + output.erase(pos); + } + + // remove \n + pos = 0; + while ((pos = output.find('\n', pos)) != std::string::npos) { + output.erase(pos); + } +} + +/** Return true if the machine is 64 bits */ +bool SystemInformationImplementation::Is64Bits() const +{ + return this->OSIs64Bit; +} +} diff --git a/SystemInformation.hxx.in b/SystemInformation.hxx.in new file mode 100644 index 0000000000..c8efd51d00 --- /dev/null +++ b/SystemInformation.hxx.in @@ -0,0 +1,163 @@ +/* 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 /* size_t */ +#include + +namespace @KWSYS_NAMESPACE@ { + +// forward declare the implementation class +class SystemInformationImplementation; + +class @KWSYS_NAMESPACE@_EXPORT SystemInformation +{ + 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 + long long 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. + long long 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. + long long 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. + long long GetProcMemoryAvailable(const char* hostLimitEnvVarName = nullptr, + const char* procLimitEnvVarName = nullptr); + + // Get the system RAM used by all processes on the host, in units of KiB. + long long GetHostMemoryUsed(); + + // Get system RAM used by this process id in units of KiB. + long long GetProcMemoryUsed(); + + // Return the load average of the machine or -0.0 if it cannot + // be determined. + double GetLoadAverage(); + + // enable/disable stack trace signal handler. In order to + // produce an informative stack trace the application should + // be dynamically linked and compiled with debug symbols. + static void SetStackTraceOnError(int enable); + + // format and return the current program stack in a string. In + // order to produce an informative stack trace the application + // should be dynamically linked and compiled with debug symbols. + static std::string GetProgramStack(int firstFrame, int wholePath); + + /** Run the different checks */ + void RunCPUCheck(); + void RunOSCheck(); + void RunMemoryCheck(); +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/SystemTools.cxx b/SystemTools.cxx new file mode 100644 index 0000000000..6144d9c04d --- /dev/null +++ b/SystemTools.cxx @@ -0,0 +1,4694 @@ +/* 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(__MINGW32__)) +# define KWSYS_WINDOWS_DIRS +#else +# if defined(__SUNPRO_CC) +# include +# 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 +#include +#include +#include +#include +#include +#include + +// 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 +#include +#ifdef __QNX__ +# include /* for malloc/free on QNX */ +#endif +#include +#include +#include +#include + +#if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__) +# include /* for strcasecmp */ +#endif + +#ifdef _MSC_VER +# define umask _umask +#endif + +// support for realpath call +#ifndef _WIN32 +# include +# include +# include +# include +# include +# include +# include +# ifndef __VMS +# include +# include +# endif +# include /* sigprocmask */ +#endif + +#ifdef __linux +# include +#endif + +// Windows API. +#if defined(_WIN32) +# include +# include +# ifndef INVALID_FILE_ATTRIBUTES +# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +# endif +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# endif +#endif + +#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H +extern char** environ; +#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]+))?/" \ + "(.+)?" +#define VTK_URL_BYTE_REGEX "%[0-9a-fA-F][0-9a-fA-F]" +#ifdef _MSC_VER +# include +#else +# include +#endif + +// This is a hack to prevent warnings about these functions being +// declared but not referenced. +#if defined(__sgi) && !defined(__GNUC__) +# include +namespace KWSYS_NAMESPACE { +class SystemToolsHack +{ +public: + enum + { + Ref1 = sizeof(cfgetospeed(0)), + Ref2 = sizeof(cfgetispeed(0)), + Ref3 = sizeof(tcgetattr(0, 0)), + Ref4 = sizeof(tcsetattr(0, 0, 0)), + Ref5 = sizeof(cfsetospeed(0, 0)), + Ref6 = sizeof(cfsetispeed(0, 0)) + }; +}; +} +#endif + +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__MINGW32__)) +# include +# include +# define _unlink unlink +#endif + +/* The maximum length of a file name. */ +#if defined(PATH_MAX) +# define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX +#elif defined(MAXPATHLEN) +# define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN +#else +# define KWSYS_SYSTEMTOOLS_MAXPATH 16384 +#endif + +#if defined(__BEOS__) && !defined(__ZETA__) +# include +# include + +// BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. +static inline void usleep(unsigned int msec) +{ + ::snooze(msec); +} + +// BeOS 5 also doesn't have realpath(), but its C++ API offers something close. +static inline char* realpath(const char* path, char* resolved_path) +{ + const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH; + snprintf(resolved_path, maxlen, "%s", path); + BPath normalized(resolved_path, 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 +# ifdef _MSC_VER +typedef KWSYS_NAMESPACE::SystemTools::mode_t mode_t; +# endif + +inline int Mkdir(const std::string& dir, const mode_t* mode) +{ + int ret = + _wmkdir(KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); + if (ret == 0 && mode) + KWSYS_NAMESPACE::SystemTools::SetPermissions(dir, *mode); + return ret; +} +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 w_buf(len); + if (_wgetcwd(&w_buf[0], len)) { + size_t nlen = kwsysEncoding_wcstombs(buf, &w_buf[0], len); + if (nlen == static_cast(-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) +{ + return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str()); +} +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 + +# include +# include +inline int Mkdir(const std::string& dir, const mode_t* mode) +{ + return mkdir(dir.c_str(), mode ? *mode : 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() +{ +#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 +using envchar = char; +#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(leq - l) : strlen(l); + size_t rlen = req ? static_cast(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 +{ +public: + class Free + { + const envchar* Env; + + public: + Free(const envchar* env) + : Env(env) + { + } + ~Free() { free(const_cast(this->Env)); } + + Free(const Free&) = delete; + Free& operator=(const Free&) = delete; + }; + + const envchar* Release(const envchar* env) + { + const envchar* old = nullptr; + auto 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: + using StringMap = std::map; +#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 PathCaseMap; + std::map 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& userPaths = std::vector(), + bool no_system_path = false); +}; + +// Do NOT initialize. Default initialization to zero is necessary. +static SystemToolsStatic* SystemToolsStatics; + +#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 path_components; + SystemTools::SplitPath(pathIn, path_components); + + // Start with root component. + std::vector::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 = SystemToolsStatics->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& 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 (auto 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 = SystemToolsStatics->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(*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 + // Remove any 'e', which is supported on UNIX, but not Windows. + std::wstring trimmedMode = Encoding::ToWide(mode); + trimmedMode.erase(std::remove(trimmedMode.begin(), trimmedMode.end(), L'e'), + trimmedMode.end()); + return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(), + trimmedMode.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) { + // all underlying functions use C strings, so temporarily + // end the string here + dir[pos] = '\0'; + + Mkdir(dir, mode); + dir[pos] = '/'; + + ++pos; + } + topdir = dir; + if (Mkdir(topdir, mode) != 0) { + // if it is some other error besides directory exists + // then return false + if (errno != EEXIST) { + return false; + } + } + + return true; +} + +// replace replace with with as many times as it shows up in source. +// write the result into source. +void SystemTools::ReplaceString(std::string& source, + const std::string& replace, + const std::string& with) +{ + // do while hangs if replaceSize is 0 + if (replace.empty()) { + return; + } + + 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(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 hasPrefix(const std::string& s, const char* pattern, + std::string::size_type spos) +{ + size_t plen = strlen(pattern); + if (spos != plen) + return false; + return s.compare(0, plen, pattern) == 0; +} + +static bool SystemToolsParseRegistryKey(const std::string& key, + HKEY& primaryKey, std::wstring& second, + std::string* valuename) +{ + size_t start = key.find('\\'); + if (start == std::string::npos) { + return false; + } + + size_t valuenamepos = key.find(';'); + if (valuenamepos != std::string::npos && valuename) { + *valuename = key.substr(valuenamepos + 1); + } + + second = Encoding::ToWide(key.substr(start + 1, valuenamepos - start - 1)); + + if (hasPrefix(key, "HKEY_CURRENT_USER", start)) { + primaryKey = HKEY_CURRENT_USER; + } else if (hasPrefix(key, "HKEY_CURRENT_CONFIG", start)) { + primaryKey = HKEY_CURRENT_CONFIG; + } else if (hasPrefix(key, "HKEY_CLASSES_ROOT", start)) { + primaryKey = HKEY_CLASSES_ROOT; + } else if (hasPrefix(key, "HKEY_LOCAL_MACHINE", start)) { + primaryKey = HKEY_LOCAL_MACHINE; + } else if (hasPrefix(key, "HKEY_USERS", start)) { + 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& subkeys, + KeyWOW64 view) +{ + HKEY primaryKey = HKEY_CURRENT_USER; + std::wstring second; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, nullptr)) { + return false; + } + + HKEY hKey; + if (RegOpenKeyExW(primaryKey, 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&, 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::wstring second; + std::string valuename; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) { + return false; + } + + HKEY hKey; + if (RegOpenKeyExW(primaryKey, 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::wstring second; + std::string valuename; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) { + return false; + } + + HKEY hKey; + DWORD dwDummy; + wchar_t lpClass[] = L""; + if (RegCreateKeyExW(primaryKey, 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::wstring second; + std::string valuename; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) { + return false; + } + + HKEY hKey; + if (RegOpenKeyExW(primaryKey, second.c_str(), 0, + SystemToolsMakeRegistryMode(KEY_WRITE, view), + &hKey) != ERROR_SUCCESS) { + return false; + } else { + if (RegDeleteValue(hKey, (LPTSTR)valuename.c_str()) == ERROR_SUCCESS) { + RegCloseKey(hKey); + return true; + } + } + return false; +} +#else +bool SystemTools::DeleteRegistryValue(const 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(_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(_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); + return _wstat64(wpath.c_str(), buf); +#else + return stat(path.c_str(), buf); +#endif +} + +bool SystemTools::Touch(const std::string& filename, bool create) +{ + if (!SystemTools::FileExists(filename)) { + if (create) { + FILE* file = Fopen(filename, "a+b"); + if (file) { + fclose(file); + return true; + } + return false; + } else { + return true; + } + } +#if defined(_WIN32) && !defined(__CYGWIN__) + HANDLE h = CreateFileW(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(toupper(s[0])); + for (size_t i = 1; i < s.size(); i++) { + n[i] = static_cast(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(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(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(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(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.empty() || max_len == 0 || max_len >= s.size()) { + return s; + } + + std::string n; + n.reserve(max_len); + + size_t middle = max_len / 2; + + n.assign(s, 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 SystemTools::SplitString(const std::string& p, + char sep, bool isPath) +{ + std::string path = p; + std::vector paths; + if (path.empty()) { + return paths; + } + if (isPath && path[0] == '/') { + path.erase(path.begin()); + paths.emplace_back("/"); + } + std::string::size_type pos1 = 0; + std::string::size_type pos2 = path.find(sep, pos1); + 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(va_arg(ap, double)); + } break; + default: { + // Assume the argument contributes no more than 64 characters. + length += 64; + + // Eat the argument. + static_cast(va_arg(ap, int)); + } break; + } + } + + // Move past the characters just tested. + ++cur; + } + } + + return static_cast(length); +} + +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"); + char oldch = path[idx]; + path[idx] = '\0'; + passwd* pw = getpwnam(path.c_str() + 1); + path[idx] = oldch; + 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(0), + static_cast(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); + if (!SystemTools::ComparePath(new_destination, destination)) { + return SystemTools::CopyFileIfDifferent(source, new_destination); + } + } else { + // 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(nleft); + finSource.read(source_buf, nnext); + finDestination.read(dest_buf, nnext); + + // If either failed to read assume they are different. + if (static_cast(finSource.gcount()) != nnext || + static_cast(finDestination.gcount()) != nnext) { + return true; + } + + // If this block differs the file differs. + if (memcmp(static_cast(source_buf), + static_cast(dest_buf), + static_cast(nnext)) != 0) { + return true; + } + + // Update the byte count remaining. + nleft -= nnext; + } + + // No differences found. + return false; +} + +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 + kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); + 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); + + kwsys::ofstream fout(destination.c_str(), + std::ios::out | std::ios::trunc | std::ios::binary); + 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(fileNum)), ".") != 0 && + strcmp(dir.GetFile(static_cast(fileNum)), "..") != 0) { + std::string fullPath = source; + fullPath += "/"; + fullPath += dir.GetFile(static_cast(fileNum)); + if (SystemTools::FileIsDirectory(fullPath)) { + std::string fullDestPath = destination; + fullDestPath += "/"; + fullDestPath += dir.GetFile(static_cast(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(fs.nFileSizeLow); + } +#else + struct stat fs; + if (stat(filename.c_str(), &fs) == 0) { + length = static_cast(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(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(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(fileNum)), ".") != 0 && + strcmp(dir.GetFile(static_cast(fileNum)), "..") != 0) { + std::string fullPath = source; + fullPath += "/"; + fullPath += dir.GetFile(static_cast(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& userPaths, + bool no_system_path) +{ + // Add the system search path to our path first + std::vector 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& 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& 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& 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& userPaths, + bool no_system_path) +{ + std::string tryPath; + +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) + std::vector 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::FileIsExecutable(tryPath)) { + return SystemTools::CollapseFullPath(tryPath); + } + } + } +#endif + + // now try just the name + if (SystemTools::FileIsExecutable(name)) { + return SystemTools::CollapseFullPath(name); + } + // now construct the path + std::vector 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::FileIsExecutable(tryPath)) { + return SystemTools::CollapseFullPath(tryPath); + } + } +#endif + // now try it without them + tryPath = p; + tryPath += name; + if (SystemTools::FileIsExecutable(tryPath)) { + return SystemTools::CollapseFullPath(tryPath); + } + } + // Couldn't find the program. + return ""; +} + +std::string SystemTools::FindProgram(const std::vector& names, + const std::vector& 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& 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 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::FileIsExecutable(const std::string& name) +{ +#if defined(_WIN32) + return SystemTools::FileExists(name, true); +#else + return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE); +#endif +} + +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(&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( + 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() +{ + char buf[2048]; + const char* cwd = Getcwd(buf, 2048); + std::string path; + if (cwd) { + path = cwd; + SystemTools::ConvertToUnixSlashes(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.clear(); + 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.resize(slashPos); + } else { + file = dir; + dir.clear(); + } + } + 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 failures; + std::string self = argv0 ? argv0 : ""; + failures.push_back(self); + SystemTools::ConvertToUnixSlashes(self); + self = SystemTools::FindProgram(self); + if (!SystemTools::FileIsExecutable(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::FileIsExecutable(self)) { + failures.push_back(self); + self = installPrefix; + self += "/bin/"; + self += exeName; + } + } + if (!SystemTools::FileIsExecutable(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; +} + +#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)) { + SystemToolsStatics->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 : SystemToolsStatics->TranslationMap) { + // We need to check of the path is a substring of the other path + if (path.compare(0, pair.first.size(), 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& out_components, + std::vector::iterator first, + std::vector::iterator last) +{ + static const std::string up = ".."; + static const std::string cur = "."; + for (std::vector::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)); + } + } +} + +namespace { + +std::string CollapseFullPathImpl(std::string const& in_path, + std::string const* in_base) +{ + // Collect the output path components. + std::vector out_components; + + // Split the input path components. + std::vector 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 base_components; + + if (in_base) { + // Use the given base path. + SystemTools::SplitPath(*in_base, base_components); + } else { + // Use the current working directory as a base path. + std::string cwd = SystemTools::GetCurrentWorkingDirectory(); + SystemTools::SplitPath(cwd, 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 = SystemToolsStatics->GetActualCaseForPathCached(newPath); + SystemTools::ConvertToUnixSlashes(newPath); +#endif + // Return the reconstructed path. + return newPath; +} +} + +std::string SystemTools::CollapseFullPath(std::string const& in_path) +{ + return CollapseFullPathImpl(in_path, nullptr); +} + +std::string SystemTools::CollapseFullPath(std::string const& in_path, + const char* in_base) +{ + if (!in_base) { + return CollapseFullPathImpl(in_path, nullptr); + } + std::string tmp_base = in_base; + return CollapseFullPathImpl(in_path, &tmp_base); +} + +std::string SystemTools::CollapseFullPath(std::string const& in_path, + std::string const& in_base) +{ + return CollapseFullPathImpl(in_path, &in_base); +} + +// 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 localSplit = SystemTools::SplitString(l, '/', true); + std::vector remoteSplit = + SystemTools::SplitString(r, '/', true); + std::vector + commonPath; // store shared parts of path in this array + std::vector finalPath; // store the final relative path here + // count up how many matching directory names there are from the start + unsigned int sameCount = 0; + while (((sameCount <= (localSplit.size() - 1)) && + (sameCount <= (remoteSplit.size() - 1))) && +// for Windows and Apple do a case insensitive string compare +#if defined(_WIN32) || defined(__APPLE__) + SystemTools::Strucmp(localSplit[sameCount].c_str(), + remoteSplit[sameCount].c_str()) == 0 +#else + localSplit[sameCount] == remoteSplit[sameCount] +#endif + ) { + // put the common parts of the path into the commonPath array + commonPath.push_back(localSplit[sameCount]); + // erase the common parts of the path from the original path arrays + localSplit[sameCount] = ""; + remoteSplit[sameCount] = ""; + sameCount++; + } + + // If there is nothing in common at all then just return the full + // path. This is the case only on windows when the paths have + // different drive letters. On unix two full paths always at least + // have the root "/" in common so we will return a relative path + // that passes through the root directory. + if (sameCount == 0) { + return remote; + } + + // for each entry that is not common in the local path + // add a ../ to the finalpath array, this gets us out of the local + // path into the remote dir + for (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& 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.resize(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.emplace_back(first, last); + first = last + 1; + } + } + + // Save the last component unless there were no components. + if (last != c) { + components.emplace_back(first, last); + } +} + +std::string SystemTools::JoinPath(const std::vector& components) +{ + return SystemTools::JoinPath(components.begin(), components.end()); +} + +std::string SystemTools::JoinPath( + std::vector::const_iterator first, + std::vector::const_iterator last) +{ + // Construct result in a single string. + std::string result; + size_t len = 0; + for (auto 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& 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& 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 == 0) { + return "/"; + } + if (slash_pos == 2 && fn[1] == ':') { + // keep the / after a drive letter + fn.resize(3); + return fn; + } + if (slash_pos == std::string::npos) { + return ""; + } + fn.resize(slash_pos); + return fn; +} + +/** + * 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) { + name.erase(0, dot_pos); + return name; + } 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) { + name.erase(0, dot_pos); + return name; + } 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) { + name.resize(dot_pos); + } + 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) { + name.resize(dot_pos); + } + 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 + + auto* 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(read_length - text_count) / + static_cast(read_length)); + + if (current_percent_bin >= percent_bin) { + return SystemTools::FileTypeBinary; + } + + return SystemTools::FileTypeText; +} + +bool SystemTools::LocateFileInDir(const char* filename, const char* dir, + 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.resize(path.length() - 1); + tempPath.erase(0, 1); + } + + std::wstring wtempPath = Encoding::ToWide(tempPath); + DWORD ret = GetShortPathNameW(wtempPath.c_str(), nullptr, 0); + std::vector buffer(ret); + if (ret != 0) { + ret = GetShortPathNameW(wtempPath.c_str(), &buffer[0], + static_cast(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(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(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; + } + subdir.resize(dir.size()); + return SystemTools::ComparePath(subdir, 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, bool decode) +{ + // 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); + + if (decode) { + dataglom = DecodeURL(dataglom); + } + + 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, bool decode) +{ + 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); + + if (decode) { + username = DecodeURL(username); + password = DecodeURL(password); + hostname = DecodeURL(hostname); + dataport = DecodeURL(dataport); + database = DecodeURL(database); + } + + return true; +} + +// ---------------------------------------------------------------------- +std::string SystemTools::DecodeURL(const std::string& url) +{ + kwsys::RegularExpression urlByteRe(VTK_URL_BYTE_REGEX); + std::string ret; + for (size_t i = 0; i < url.length(); i++) { + if (urlByteRe.find(url.substr(i, 3))) { + char bytes[] = { url[i + 1], url[i + 2], '\0' }; + ret += static_cast(strtoul(bytes, nullptr, 16)); + i += 2; + } else { + ret += url[i]; + } + } + return ret; +} + +// ---------------------------------------------------------------------- +// Do NOT initialize. Default initialization to zero is necessary. +static unsigned int SystemToolsManagerCount; + +// 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 + SystemToolsStatics = 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 SystemToolsStatics; +} + +} // namespace KWSYS_NAMESPACE + +#if defined(_MSC_VER) && defined(_DEBUG) +# include +# include +# include +namespace KWSYS_NAMESPACE { + +static int SystemToolsDebugReport(int, char* message, int* ret) +{ + if (ret) { + // Pretend user clicked on Retry button in popup. + *ret = 1; + } + fprintf(stderr, "%s", message); + fflush(stderr); + return 1; // no further reporting required +} + +void SystemTools::EnableMSVCDebugHook() +{ + if (SystemTools::HasEnv("DART_TEST_FROM_DART") || + SystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST")) { + _CrtSetReportHook(SystemToolsDebugReport); + } +} + +} // namespace KWSYS_NAMESPACE +#else +namespace KWSYS_NAMESPACE { +void SystemTools::EnableMSVCDebugHook() +{ +} +} // namespace KWSYS_NAMESPACE +#endif diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in new file mode 100644 index 0000000000..74dc176514 --- /dev/null +++ b/SystemTools.hxx.in @@ -0,0 +1,983 @@ +/* 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 +#include +#include +#include + +#include +// include sys/stat.h after sys/types.h +#include + +#if !defined(_WIN32) || defined(__CYGWIN__) +# include // For access permissions for use with access() +#endif + +// Required for va_list +#include +// Required for FILE* +#include +#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), 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 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& l); + static bool Split(const std::string& s, std::vector& l, + char separator); + + /** + * Return string with space added between capitalized words + * (i.e. EatMyShorts becomes Eat My Shorts ) + * (note that IEatShorts becomes IEat Shorts) + */ + static 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__) + typedef struct _stat64 Stat_t; +#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); + + /** + * 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(std::string const& in_path); + static std::string CollapseFullPath(std::string const& in_path, + const char* in_base); + static std::string CollapseFullPath(std::string const& in_path, + std::string const& 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& 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& components); + static std::string JoinPath(std::vector::const_iterator first, + std::vector::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. On Windows, if 'e' is present in + * mode it is first discarded. + */ + static FILE* Fopen(const std::string& file, const char* mode); + +/** + * Visual C++ does not define mode_t. + */ +#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& path = std::vector(), + 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& path = std::vector(), + 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& path = std::vector(), + bool no_system_path = false); + static std::string FindProgram( + const std::string& name, + const std::vector& path = std::vector(), + bool no_system_path = false); + static std::string FindProgram( + const std::vector& names, + const std::vector& path = std::vector(), + 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& path); + + /** + * Return true if the file is a directory + */ + static bool FileIsDirectory(const std::string& name); + + /** + * Return true if the file is an executable + */ + static bool FileIsExecutable(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& 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& 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(); + + /** + * 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. + * decode the dataglom using DecodeURL if set to true. + * 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, bool decode = false); + + /** + * 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. + * decode all string except the protocol using DecodeUrl if set to true. + * 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, bool decode = false); + + /** + * Decode the percent-encoded string from an URL or an URI + * into their correct char values. + * Does not perform any other sort of validation. + * Return the decoded string + */ + static std::string DecodeURL(const std::string& url); + +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; + } + + friend class SystemToolsStatic; + friend class SystemToolsManager; +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/Terminal.c b/Terminal.c new file mode 100644 index 0000000000..4d1b46c871 --- /dev/null +++ b/Terminal.c @@ -0,0 +1,423 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#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 /* va_list */ +#include /* getenv */ +#include /* strcmp */ + +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) +# include /* _get_osfhandle */ +# include /* SetConsoleTextAttribute */ +#endif + +#if defined(KWSYS_TERMINAL_ISATTY_WORKS) +# include /* isatty */ +#else +# include /* fstat */ +#endif + +static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, + int default_tty); +static void kwsysTerminalSetVT100Color(FILE* stream, int color); +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) +static HANDLE kwsysTerminalGetStreamHandle(FILE* stream); +static void kwsysTerminalSetConsoleColor(HANDLE hOut, + CONSOLE_SCREEN_BUFFER_INFO* hOutInfo, + FILE* stream, int color); +#endif + +void kwsysTerminal_cfprintf(int color, FILE* stream, const char* format, ...) +{ + /* Setup the stream with the given color if possible. */ + int pipeIsConsole = 0; + int pipeIsVT100 = 0; + int default_vt100 = color & kwsysTerminal_Color_AssumeVT100; + int default_tty = color & kwsysTerminal_Color_AssumeTTY; +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) + CONSOLE_SCREEN_BUFFER_INFO hOutInfo; + HANDLE hOut = kwsysTerminalGetStreamHandle(stream); + if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) { + pipeIsConsole = 1; + kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, color); + } +#endif + if (!pipeIsConsole && + kwsysTerminalStreamIsVT100(stream, default_vt100, default_tty)) { + pipeIsVT100 = 1; + kwsysTerminalSetVT100Color(stream, color); + } + + /* Format the text into the stream. */ + { + va_list var_args; + va_start(var_args, format); + vfprintf(stream, format, var_args); + va_end(var_args); + } + +/* Restore the normal color state for the stream. */ +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) + if (pipeIsConsole) { + kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, + kwsysTerminal_Color_Normal); + } +#endif + if (pipeIsVT100) { + kwsysTerminalSetVT100Color(stream, kwsysTerminal_Color_Normal); + } +} + +/* Detect cases when a stream is 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", + "st-256color", + "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; + } + } + + /* GNU make 4.1+ may tell us that its output is destined for a TTY. */ + { + const char* termout = getenv("MAKE_TERMOUT"); + if (termout && *termout != '\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 diff --git a/Terminal.h.in b/Terminal.h.in new file mode 100644 index 0000000000..1a2c7452fa --- /dev/null +++ b/Terminal.h.in @@ -0,0 +1,170 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Terminal_h +#define @KWSYS_NAMESPACE@_Terminal_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include /* For file stream type FILE. */ + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysTerminal_cfprintf kwsys_ns(Terminal_cfprintf) +# define kwsysTerminal_Color_e kwsys_ns(Terminal_Color_e) +# define kwsysTerminal_Color_Normal kwsys_ns(Terminal_Color_Normal) +# define kwsysTerminal_Color_ForegroundBlack \ + kwsys_ns(Terminal_Color_ForegroundBlack) +# define kwsysTerminal_Color_ForegroundRed \ + kwsys_ns(Terminal_Color_ForegroundRed) +# define kwsysTerminal_Color_ForegroundGreen \ + kwsys_ns(Terminal_Color_ForegroundGreen) +# define kwsysTerminal_Color_ForegroundYellow \ + kwsys_ns(Terminal_Color_ForegroundYellow) +# define kwsysTerminal_Color_ForegroundBlue \ + kwsys_ns(Terminal_Color_ForegroundBlue) +# define kwsysTerminal_Color_ForegroundMagenta \ + kwsys_ns(Terminal_Color_ForegroundMagenta) +# define kwsysTerminal_Color_ForegroundCyan \ + kwsys_ns(Terminal_Color_ForegroundCyan) +# define kwsysTerminal_Color_ForegroundWhite \ + kwsys_ns(Terminal_Color_ForegroundWhite) +# define kwsysTerminal_Color_ForegroundMask \ + kwsys_ns(Terminal_Color_ForegroundMask) +# define kwsysTerminal_Color_BackgroundBlack \ + kwsys_ns(Terminal_Color_BackgroundBlack) +# define kwsysTerminal_Color_BackgroundRed \ + kwsys_ns(Terminal_Color_BackgroundRed) +# define kwsysTerminal_Color_BackgroundGreen \ + kwsys_ns(Terminal_Color_BackgroundGreen) +# define kwsysTerminal_Color_BackgroundYellow \ + kwsys_ns(Terminal_Color_BackgroundYellow) +# define kwsysTerminal_Color_BackgroundBlue \ + kwsys_ns(Terminal_Color_BackgroundBlue) +# define kwsysTerminal_Color_BackgroundMagenta \ + kwsys_ns(Terminal_Color_BackgroundMagenta) +# define kwsysTerminal_Color_BackgroundCyan \ + kwsys_ns(Terminal_Color_BackgroundCyan) +# define kwsysTerminal_Color_BackgroundWhite \ + kwsys_ns(Terminal_Color_BackgroundWhite) +# define kwsysTerminal_Color_BackgroundMask \ + kwsys_ns(Terminal_Color_BackgroundMask) +# define kwsysTerminal_Color_ForegroundBold \ + kwsys_ns(Terminal_Color_ForegroundBold) +# define kwsysTerminal_Color_BackgroundBold \ + kwsys_ns(Terminal_Color_BackgroundBold) +# define kwsysTerminal_Color_AssumeTTY kwsys_ns(Terminal_Color_AssumeTTY) +# define kwsysTerminal_Color_AssumeVT100 kwsys_ns(Terminal_Color_AssumeVT100) +# define kwsysTerminal_Color_AttributeMask \ + kwsys_ns(Terminal_Color_AttributeMask) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Write colored and formatted text to a stream. Color is used only + * for streams supporting it. The color specification is constructed + * by bitwise-OR-ing enumeration values. At most one foreground and + * one background value may be given. + * + * Whether the a stream supports color is usually automatically + * detected, but with two exceptions: + * + * - When the stream is displayed in a terminal supporting VT100 + * color but using an intermediate pipe for communication the + * detection of a tty fails. (This typically occurs for a shell + * running in an rxvt terminal in MSYS.) If the caller knows this + * to be the case, the attribute Color_AssumeTTY may be included in + * the color specification. + * + * - When the stream is displayed in a terminal whose TERM + * environment variable is not set or is set to a value that is not + * known to support VT100 colors. If the caller knows this to be + * the case, the attribute Color_AssumeVT100 may be included in the + * color specification. + */ +kwsysEXPORT void kwsysTerminal_cfprintf(int color, FILE* stream, + const char* format, ...); +enum kwsysTerminal_Color_e +{ + /* Normal Text */ + kwsysTerminal_Color_Normal = 0, + + /* Foreground Color */ + kwsysTerminal_Color_ForegroundBlack = 0x1, + kwsysTerminal_Color_ForegroundRed = 0x2, + kwsysTerminal_Color_ForegroundGreen = 0x3, + kwsysTerminal_Color_ForegroundYellow = 0x4, + kwsysTerminal_Color_ForegroundBlue = 0x5, + kwsysTerminal_Color_ForegroundMagenta = 0x6, + kwsysTerminal_Color_ForegroundCyan = 0x7, + kwsysTerminal_Color_ForegroundWhite = 0x8, + kwsysTerminal_Color_ForegroundMask = 0xF, + + /* Background Color */ + kwsysTerminal_Color_BackgroundBlack = 0x10, + kwsysTerminal_Color_BackgroundRed = 0x20, + kwsysTerminal_Color_BackgroundGreen = 0x30, + kwsysTerminal_Color_BackgroundYellow = 0x40, + kwsysTerminal_Color_BackgroundBlue = 0x50, + kwsysTerminal_Color_BackgroundMagenta = 0x60, + kwsysTerminal_Color_BackgroundCyan = 0x70, + kwsysTerminal_Color_BackgroundWhite = 0x80, + kwsysTerminal_Color_BackgroundMask = 0xF0, + + /* Attributes */ + kwsysTerminal_Color_ForegroundBold = 0x100, + kwsysTerminal_Color_BackgroundBold = 0x200, + kwsysTerminal_Color_AssumeTTY = 0x400, + kwsysTerminal_Color_AssumeVT100 = 0x800, + kwsysTerminal_Color_AttributeMask = 0xF00 +}; + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysTerminal_cfprintf +# undef kwsysTerminal_Color_e +# undef kwsysTerminal_Color_Normal +# undef kwsysTerminal_Color_ForegroundBlack +# undef kwsysTerminal_Color_ForegroundRed +# undef kwsysTerminal_Color_ForegroundGreen +# undef kwsysTerminal_Color_ForegroundYellow +# undef kwsysTerminal_Color_ForegroundBlue +# undef kwsysTerminal_Color_ForegroundMagenta +# undef kwsysTerminal_Color_ForegroundCyan +# undef kwsysTerminal_Color_ForegroundWhite +# undef kwsysTerminal_Color_ForegroundMask +# undef kwsysTerminal_Color_BackgroundBlack +# undef kwsysTerminal_Color_BackgroundRed +# undef kwsysTerminal_Color_BackgroundGreen +# undef kwsysTerminal_Color_BackgroundYellow +# undef kwsysTerminal_Color_BackgroundBlue +# undef kwsysTerminal_Color_BackgroundMagenta +# undef kwsysTerminal_Color_BackgroundCyan +# undef kwsysTerminal_Color_BackgroundWhite +# undef kwsysTerminal_Color_BackgroundMask +# undef kwsysTerminal_Color_ForegroundBold +# undef kwsysTerminal_Color_BackgroundBold +# undef kwsysTerminal_Color_AssumeTTY +# undef kwsysTerminal_Color_AssumeVT100 +# undef kwsysTerminal_Color_AttributeMask +# endif +#endif + +#endif diff --git a/kwsysHeaderDump.pl b/kwsysHeaderDump.pl new file mode 100755 index 0000000000..e3391e7623 --- /dev/null +++ b/kwsysHeaderDump.pl @@ -0,0 +1,41 @@ +#!/usr/bin/perl +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing#kwsys for details. + +if ( $#ARGV+1 < 2 ) +{ + print "Usage: ./kwsysHeaderDump.pl
\n"; + exit(1); +} + +$name = $ARGV[0]; +$max = 0; +open(INFILE, $ARGV[1]); +while (chomp ($line = )) +{ + if (($line !~ /^\#/) && + ($line =~ s/.*kwsys${name}_([A-Za-z0-9_]*).*/\1/) && + ($i{$line}++ < 1)) + { + push(@lines, "$line"); + if (length($line) > $max) + { + $max = length($line); + } + } +} +close(INFILE); + +$width = $max + 13; +print sprintf("#define %-${width}s kwsys_ns(${name})\n", "kwsys${name}"); +foreach $l (@lines) +{ + print sprintf("#define %-${width}s kwsys_ns(${name}_$l)\n", + "kwsys${name}_$l"); +} +print "\n"; +print sprintf("# undef kwsys${name}\n"); +foreach $l (@lines) +{ + print sprintf("# undef kwsys${name}_$l\n"); +} diff --git a/kwsysPlatformTests.cmake b/kwsysPlatformTests.cmake new file mode 100644 index 0000000000..89be4b8853 --- /dev/null +++ b/kwsysPlatformTests.cmake @@ -0,0 +1,216 @@ +# 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() diff --git a/kwsysPlatformTestsC.c b/kwsysPlatformTestsC.c new file mode 100644 index 0000000000..d44f7eb9cb --- /dev/null +++ b/kwsysPlatformTestsC.c @@ -0,0 +1,71 @@ +/* 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 +int f(ptrdiff_t n) +{ + return n > 0; +} +int KWSYS_PLATFORM_TEST_C_MAIN() +{ + char* p = 0; + ptrdiff_t d = p - p; + (void)d; + return f(p - p); +} +#endif + +#ifdef TEST_KWSYS_C_HAS_SSIZE_T +# include +int f(ssize_t n) +{ + return (int)n; +} +int KWSYS_PLATFORM_TEST_C_MAIN() +{ + ssize_t n = 0; + return f(n); +} +#endif + +#ifdef TEST_KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC +# if defined(__APPLE__) +# include +# if MAC_OS_X_VERSION_MIN_REQUIRED < 101200 +# error "clock_gettime not available on macOS < 10.12" +# endif +# endif +# include +int KWSYS_PLATFORM_TEST_C_MAIN() +{ + struct timespec ts; + return clock_gettime(CLOCK_MONOTONIC, &ts); +} +#endif diff --git a/kwsysPlatformTestsCXX.cxx b/kwsysPlatformTestsCXX.cxx new file mode 100644 index 0000000000..0bfa20ee1d --- /dev/null +++ b/kwsysPlatformTestsCXX.cxx @@ -0,0 +1,174 @@ +/* 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_STAT_HAS_ST_MTIM +# include + +# include +# include +int main() +{ + struct stat stat1; + (void)stat1.st_mtim.tv_sec; + (void)stat1.st_mtim.tv_nsec; + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIMESPEC +# include + +# include +# include +int main() +{ + struct stat stat1; + (void)stat1.st_mtimespec.tv_sec; + (void)stat1.st_mtimespec.tv_nsec; + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_SETENV +# include +int main() +{ + return setenv("A", "B", 1); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UNSETENV +# include +int main() +{ + unsetenv("A"); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H +# include +int main() +{ + char* e = environ[0]; + return e ? 0 : 1; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_GETLOADAVG +// Match feature definitions from SystemInformation.cxx +# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# include +int main() +{ + double loadavg[3] = { 0.0, 0.0, 0.0 }; + return getloadavg(loadavg, 3); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64 +# include +int main() +{ + struct rlimit64 rlim; + return getrlimit64(0, &rlim); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UTIMES +# include +int main() +{ + struct timeval* current_time = 0; + return utimes("/example", current_time); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UTIMENSAT +# include +# include +# if defined(__APPLE__) +# include +# 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 +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 +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 +# endif +# include +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_STL_HAS_WSTRING +# include +void f(std::wstring*) +{ +} +int main() +{ + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H +# include +int main() +{ + return 0; +} +#endif diff --git a/kwsysPrivate.h b/kwsysPrivate.h new file mode 100644 index 0000000000..dd9c1277fb --- /dev/null +++ b/kwsysPrivate.h @@ -0,0 +1,34 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef KWSYS_NAMESPACE +# error "Do not include kwsysPrivate.h outside of kwsys c and cxx files." +#endif + +#ifndef _kwsysPrivate_h +# define _kwsysPrivate_h + +/* + Define KWSYS_HEADER macro to help the c and cxx files include kwsys + headers from the configured namespace directory. The macro can be + used like this: + + #include KWSYS_HEADER(Directory.hxx) + #include KWSYS_HEADER(std/vector) +*/ +/* clang-format off */ +#define KWSYS_HEADER(x) KWSYS_HEADER0(KWSYS_NAMESPACE/x) +/* clang-format on */ +# define KWSYS_HEADER0(x) KWSYS_HEADER1(x) +# define KWSYS_HEADER1(x) + +/* + Define KWSYS_NAMESPACE_STRING to be a string constant containing the + name configured for this instance of the kwsys library. +*/ +# define KWSYS_NAMESPACE_STRING KWSYS_NAMESPACE_STRING0(KWSYS_NAMESPACE) +# define KWSYS_NAMESPACE_STRING0(x) KWSYS_NAMESPACE_STRING1(x) +# define KWSYS_NAMESPACE_STRING1(x) # x + +#else +# error "kwsysPrivate.h included multiple times." +#endif diff --git a/testCommandLineArguments.cxx b/testCommandLineArguments.cxx new file mode 100644 index 0000000000..0786751592 --- /dev/null +++ b/testCommandLineArguments.cxx @@ -0,0 +1,209 @@ +/* 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 +#include + +#include /* size_t */ +#include /* strcmp */ + +static void* random_ptr = reinterpret_cast(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 numbers_argument; + int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 }; + + std::vector doubles_argument; + double valid_doubles[] = { 12.5, 1.31, 22 }; + + std::vector bools_argument; + bool valid_bools[] = { true, true, false }; + + std::vector strings_argument; + const char* valid_strings[] = { "andy", "bill", "brad", "ken" }; + + std::vector stl_strings_argument; + std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" }; + + using argT = kwsys::CommandLineArguments; + + 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; +} diff --git a/testCommandLineArguments1.cxx b/testCommandLineArguments1.cxx new file mode 100644 index 0000000000..2f6b735784 --- /dev/null +++ b/testCommandLineArguments1.cxx @@ -0,0 +1,91 @@ +/* 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 +#include + +#include /* assert */ +#include /* 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; + + using argT = kwsys::CommandLineArguments; + 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; + 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; +} diff --git a/testConfigure.cxx b/testConfigure.cxx new file mode 100644 index 0000000000..a3c2ed3aed --- /dev/null +++ b/testConfigure.cxx @@ -0,0 +1,30 @@ +/* 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; +} diff --git a/testConsoleBuf.cxx b/testConsoleBuf.cxx new file mode 100644 index 0000000000..4b7ddf053f --- /dev/null +++ b/testConsoleBuf.cxx @@ -0,0 +1,782 @@ +/* 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 +# include +# include +# include +# include +# include +# include + +# 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* errstream(const char* unused) +{ + static_cast(unused); + return std::cerr.rdbuf(); +} + +std::basic_streambuf* errstream(const wchar_t* unused) +{ + static_cast(unused); + return std::wcerr.rdbuf(); +} + +template +static void dumpBuffers(const T* expected, const T* received, size_t size) +{ + std::basic_ostream err(errstream(expected)); + err << "Expected output: '" << std::basic_string(expected, size) << "'" + << std::endl; + if (err.fail()) { + err.clear(); + err << "--- Error while outputting ---" << std::endl; + } + err << "Received output: '" << std::basic_string(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(expected[i]) + << " | " + << "0x" << std::setw(8) + << static_cast(received[i]); + if (static_cast(expected[i]) != + static_cast(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(encodedTestString.c_str(), buffer, + encodedTestString.size()); + dumpBuffers(encodedInputTestString.c_str(), + buffer + encodedTestString.size() + 1, + encodedInputTestString.size()); + dumpBuffers(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(encodedTestString.c_str(), buffer, + encodedTestString.size()); + dumpBuffers(encodedInputTestString.c_str(), + buffer + encodedTestString.size() + 1, + encodedInputTestString.size()); + dumpBuffers(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(wideTestString.c_str(), outputBuffer, + wideTestString.size()); + dumpBuffers(wideTestString.c_str(), + outputBuffer + screenBufferInfo.dwSize.X * 1, + wideTestString.size()); + dumpBuffers( + UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2, + (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR)); + dumpBuffers(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; +} diff --git a/testConsoleBuf.hxx b/testConsoleBuf.hxx new file mode 100644 index 0000000000..e93cb4f0a1 --- /dev/null +++ b/testConsoleBuf.hxx @@ -0,0 +1,17 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef testConsoleBuf_hxx +#define testConsoleBuf_hxx + +static const wchar_t cmdConsoleBufChild[] = L"testConsoleBufChild"; + +static const wchar_t BeforeInputEventName[] = L"BeforeInputEvent"; +static const wchar_t AfterOutputEventName[] = L"AfterOutputEvent"; + +// यूनिकोड είναι здорово! +static const wchar_t UnicodeTestString[] = + L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 " + L"\u03B5\u03AF\u03BD\0\u03B1\u03B9 " + L"\u0437\u0434\u043E\u0440\u043E\u0432\u043E!"; + +#endif diff --git a/testConsoleBufChild.cxx b/testConsoleBufChild.cxx new file mode 100644 index 0000000000..3c8fdc2e13 --- /dev/null +++ b/testConsoleBufChild.cxx @@ -0,0 +1,55 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +#include KWSYS_HEADER(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 + +#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(argc); + static_cast(argv); +#endif + return 0; +} diff --git a/testDirectory.cxx b/testDirectory.cxx new file mode 100644 index 0000000000..eb3ca3254c --- /dev/null +++ b/testDirectory.cxx @@ -0,0 +1,143 @@ +/* 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 +#include +#include + +#include + +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 + std::string errorMessage = ""; + res += !testdir.Load(testdirpath, &errorMessage); + if (errorMessage != "") { + std::cerr << "Failed to list directory: " << errorMessage << std::endl; + } + // 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 _nonExistentDirectoryTest() +{ + using namespace kwsys; + int res = 0; + std::string testdirpath(TEST_SYSTEMTOOLS_BINARY_DIR + "/directory_testing/doesnt_exist/"); + std::string errorMessage; + Directory testdir; + + errorMessage = "foo"; + // Increment res failure if directory lists + res += testdir.Load(testdirpath, &errorMessage); +#if !defined(_WIN32) || defined(__CYGWIN__) + // Increment res failure if errorMessage is unmodified + res += (errorMessage == "foo"); +#endif + + errorMessage = "foo"; + // Increment res failure if directory has files + res += (testdir.GetNumberOfFilesInDirectory(testdirpath, &errorMessage) > 0); +#if !defined(_WIN32) || defined(__CYGWIN__) + // Increment res failure if errorMessage is unmodified + res += (errorMessage == "foo"); +#endif + + 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() + _nonExistentDirectoryTest() + + _copyDirectoryTest(); +} diff --git a/testDynamicLoader.cxx b/testDynamicLoader.cxx new file mode 100644 index 0000000000..703ad4dcd4 --- /dev/null +++ b/testDynamicLoader.cxx @@ -0,0 +1,133 @@ +/* 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 /* 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 +#include + +// Include with <> instead of "" to avoid getting any in-source copy +// left on disk. +#include + +static std::string GetLibName(const char* lname, const char* subdir = nullptr) +{ + // Construct proper name of lib + std::string slname; + slname = RUNTIME_OUTPUT_DIRECTORY; + 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; +} diff --git a/testDynload.c b/testDynload.c new file mode 100644 index 0000000000..33a431e9d0 --- /dev/null +++ b/testDynload.c @@ -0,0 +1,13 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef _WIN32 +# define DL_EXPORT __declspec(dllexport) +#else +# define DL_EXPORT +#endif + +DL_EXPORT int TestDynamicLoaderData = 0; + +DL_EXPORT void TestDynamicLoaderSymbolPointer(void) +{ +} diff --git a/testDynloadImpl.c b/testDynloadImpl.c new file mode 100644 index 0000000000..2b9069bc7a --- /dev/null +++ b/testDynloadImpl.c @@ -0,0 +1,10 @@ +/* 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() +{ +} diff --git a/testDynloadImpl.h b/testDynloadImpl.h new file mode 100644 index 0000000000..d0c9dfb756 --- /dev/null +++ b/testDynloadImpl.h @@ -0,0 +1,15 @@ +/* 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(); diff --git a/testDynloadUse.c b/testDynloadUse.c new file mode 100644 index 0000000000..5402add6a2 --- /dev/null +++ b/testDynloadUse.c @@ -0,0 +1,15 @@ +/* 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; +} diff --git a/testEncode.c b/testEncode.c new file mode 100644 index 0000000000..b7b6dd8458 --- /dev/null +++ b/testEncode.c @@ -0,0 +1,67 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(MD5.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "MD5.h.in" +#endif + +#include +#include + +static const unsigned char testMD5input1[] = + " A quick brown fox jumps over the lazy dog.\n" + " This is sample text for MD5 sum input.\n"; +static const char testMD5output1[] = "8f146af46ed4f267921bb937d4d3500c"; + +static const int testMD5input2len = 28; +static const unsigned char testMD5input2[] = "the cow jumped over the moon"; +static const char testMD5output2[] = "a2ad137b746138fae4e5adca9c85d3ae"; + +static int testMD5_1(kwsysMD5* md5) +{ + char md5out[33]; + kwsysMD5_Initialize(md5); + kwsysMD5_Append(md5, testMD5input1, -1); + kwsysMD5_FinalizeHex(md5, md5out); + md5out[32] = 0; + printf("md5sum 1: expected [%s]\n" + " got [%s]\n", + testMD5output1, md5out); + return (strcmp(md5out, testMD5output1) != 0) ? 1 : 0; +} + +static int testMD5_2(kwsysMD5* md5) +{ + unsigned char digest[16]; + char md5out[33]; + kwsysMD5_Initialize(md5); + kwsysMD5_Append(md5, testMD5input2, testMD5input2len); + kwsysMD5_Finalize(md5, digest); + kwsysMD5_DigestToHex(digest, md5out); + md5out[32] = 0; + printf("md5sum 2: expected [%s]\n" + " got [%s]\n", + testMD5output2, md5out); + return (strcmp(md5out, testMD5output2) != 0) ? 1 : 0; +} + +int testEncode(int argc, char* argv[]) +{ + int result = 0; + (void)argc; + (void)argv; + + /* Test MD5 digest. */ + { + kwsysMD5* md5 = kwsysMD5_New(); + result |= testMD5_1(md5); + result |= testMD5_2(md5); + kwsysMD5_Delete(md5); + } + + return result; +} diff --git a/testEncoding.cxx b/testEncoding.cxx new file mode 100644 index 0000000000..ee93e8d8dc --- /dev/null +++ b/testEncoding.cxx @@ -0,0 +1,285 @@ +/* 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 +#include +#include +#include +#include + +// 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(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()) != 0)) { + 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.empty()) { + 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.empty()) { + 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.empty()) { + std::cout << "ToNarrow(NULL) returned " << str << std::endl; + ret++; + } + + str = kwsys::Encoding::ToNarrow(L""); + if (!wstr.empty()) { + std::cout << "ToNarrow(\"\") returned " << str << std::endl; + ret++; + } + + std::cout.flags(flags); + return ret; +} + +static int testWithNulls() +{ + int ret = 0; + std::vector 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 (auto& string : strings) { + std::wstring wstr = kwsys::Encoding::ToWide(string); + std::string str = kwsys::Encoding::ToNarrow(wstr); + std::string s(string); + std::replace(s.begin(), s.end(), '\0', ' '); + std::cout << "'" << s << "' (" << string.size() << ")" << std::endl; + if (str != string) { + std::replace(str.begin(), str.end(), '\0', ' '); + std::cout << "string with null was different: '" << str << "' (" + << str.size() << ")" << std::endl; + ret++; + } + } + return ret; +} + +static int testCommandLineArguments() +{ + int status = 0; + + char const* argv[2] = { "./app.exe", (char const*)helloWorldStrings[1] }; + + kwsys::Encoding::CommandLineArguments args(2, argv); + kwsys::Encoding::CommandLineArguments arg2 = + kwsys::Encoding::CommandLineArguments(args); + + char const* const* u8_argv = args.argv(); + for (int i = 0; i < args.argc(); i++) { + char const* u8_arg = u8_argv[i]; + if (strcmp(argv[i], u8_arg) != 0) { + std::cout << "argv[" << i << "] " << argv[i] << " != " << u8_arg + << std::endl; + status++; + } + } + + kwsys::Encoding::CommandLineArguments args3 = + kwsys::Encoding::CommandLineArguments::Main(2, argv); + + return status; +} + +static int testToWindowsExtendedPath() +{ +#ifdef _WIN32 + int ret = 0; + if (kwsys::Encoding::ToWindowsExtendedPath( + "L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") != + L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"" + << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath( + "L:/Local Mojo/Hex Power Pack/Iffy Voodoo") != + L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath( + "\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") != + L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"" + << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath( + "//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") != + L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\"" + << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("//") != L"//") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"//\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\") != L"\\\\.\\") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\.\\\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X") != L"\\\\.\\X") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\.\\X\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:") != L"\\\\?\\X:") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\.\\X:\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:\\") != + L"\\\\?\\X:\\") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\.\\X:\\\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("NUL") != L"\\\\.\\NUL") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"NUL\"" << std::endl; + ++ret; + } + + return ret; +#else + return 0; +#endif +} + +int testEncoding(int, char* []) +{ + const char* loc = setlocale(LC_ALL, ""); + if (loc) { + std::cout << "Locale: " << loc << std::endl; + } else { + std::cout << "Locale: None" << std::endl; + } + + int ret = 0; + + ret |= testHelloWorldEncoding(); + ret |= testRobustEncoding(); + ret |= testCommandLineArguments(); + ret |= testWithNulls(); + ret |= testToWindowsExtendedPath(); + + return ret; +} diff --git a/testFStream.cxx b/testFStream.cxx new file mode 100644 index 0000000000..afba9530e4 --- /dev/null +++ b/testFStream.cxx @@ -0,0 +1,110 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +#if defined(_MSC_VER) +# pragma warning(disable : 4786) +#endif + +#include KWSYS_HEADER(FStream.hxx) +#include + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "FStream.hxx.in" +#endif + +#include + +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(expected_bom_data[i] + 1), + *expected_bom_data[i]); + out.write(reinterpret_cast(file_data[i] + 1), + file_data[i][0]); + } + + kwsys::ifstream in("bom.txt", kwsys::ofstream::binary); + kwsys::FStream::BOM bom = kwsys::FStream::ReadBOM(in); + if (bom != expected_bom[i]) { + std::cout << "Unexpected BOM " << i << std::endl; + return 1; + } + char data[max_test_file_size]; + in.read(data, file_data[i][0]); + if (!in.good()) { + std::cout << "Unable to read data " << i << std::endl; + return 1; + } + + if (memcmp(data, file_data[i] + 1, file_data[i][0]) != 0) { + std::cout << "Incorrect read data " << i << std::endl; + return 1; + } + } + + return 0; +} + +int testFStream(int, char* []) +{ + int ret = 0; + + ret |= testNoFile(); + ret |= testBOM(); + + return ret; +} diff --git a/testFail.c b/testFail.c new file mode 100644 index 0000000000..82caeac37f --- /dev/null +++ b/testFail.c @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include +#include +#include + +int testFail(int argc, char* argv[]) +{ + char* env = getenv("DASHBOARD_TEST_FROM_CTEST"); + int oldCtest = 0; + if (env) { + if (strcmp(env, "1") == 0) { + oldCtest = 1; + } + printf("DASHBOARD_TEST_FROM_CTEST = %s\n", env); + } + printf("%s: This test intentionally fails\n", argv[0]); + if (oldCtest) { + printf("The version of ctest is not able to handle intentionally failing " + "tests, so pass.\n"); + return 0; + } + return argc; +} diff --git a/testProcess.c b/testProcess.c new file mode 100644 index 0000000000..eed770cd85 --- /dev/null +++ b/testProcess.c @@ -0,0 +1,726 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Process.h) +#include KWSYS_HEADER(Encoding.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Encoding.h.in" +# include "Process.h.in" +#endif + +#include +#include +#include +#include +#include + +#if defined(_WIN32) +# include +#else +# include +# include +#endif + +/* Platform-specific sleep functions. */ + +#if defined(__BEOS__) && !defined(__ZETA__) +/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ +# include +static inline void testProcess_usleep(unsigned int usec) +{ + snooze(usec); +} +#elif defined(_WIN32) +/* Windows can only sleep in millisecond intervals. */ +static void testProcess_usleep(unsigned int usec) +{ + Sleep(usec / 1000); +} +#else +# define testProcess_usleep usleep +#endif + +#if defined(_WIN32) +static void testProcess_sleep(unsigned int sec) +{ + Sleep(sec * 1000); +} +#else +static void testProcess_sleep(unsigned int sec) +{ + sleep(sec); +} +#endif + +int runChild(const char* cmd[], int state, int exception, int value, int share, + int output, int delay, double timeout, int poll, int repeat, + int disown, int createNewGroup, unsigned int interruptDelay); + +static int test1(int argc, const char* argv[]) +{ + /* This is a very basic functional test of kwsysProcess. It is repeated + numerous times to verify that there are no resource leaks in kwsysProcess + that eventually lead to an error. Many versions of OS X will fail after + 256 leaked file handles, so 257 iterations seems to be a good test. On + the other hand, too many iterations will cause the test to time out - + especially if the test is instrumented with e.g. valgrind. + + If you have problems with this test timing out on your system, or want to + run more than 257 iterations, you can change the number of iterations by + setting the KWSYS_TEST_PROCESS_1_COUNT environment variable. */ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout from test returning 0.\n"); + fprintf(stderr, "Output on stderr from test returning 0.\n"); + return 0; +} + +static int test2(int argc, const char* argv[]) +{ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout from test returning 123.\n"); + fprintf(stderr, "Output on stderr from test returning 123.\n"); + return 123; +} + +static int test3(int argc, const char* argv[]) +{ + (void)argc; + (void)argv; + fprintf(stdout, "Output before sleep on stdout from timeout test.\n"); + fprintf(stderr, "Output before sleep on stderr from timeout test.\n"); + fflush(stdout); + fflush(stderr); + testProcess_sleep(15); + fprintf(stdout, "Output after sleep on stdout from timeout test.\n"); + fprintf(stderr, "Output after sleep on stderr from timeout test.\n"); + return 0; +} + +static int test4(int argc, const char* argv[]) +{ +#ifndef CRASH_USING_ABORT + /* Prepare a pointer to an invalid address. Don't use null, because + dereferencing null is undefined behaviour and compilers are free to + do whatever they want. ex: Clang will warn at compile time, or even + optimize away the write. We hope to 'outsmart' them by using + 'volatile' and a slightly larger address, based on a runtime value. */ + volatile int* invalidAddress = 0; + invalidAddress += argc ? 1 : 2; +#endif + +#if defined(_WIN32) + /* Avoid error diagnostic popups since we are crashing on purpose. */ + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); +#elif defined(__BEOS__) || defined(__HAIKU__) + /* Avoid error diagnostic popups since we are crashing on purpose. */ + disable_debugger(1); +#endif + (void)argc; + (void)argv; + fprintf(stdout, "Output before crash on stdout from crash test.\n"); + fprintf(stderr, "Output before crash on stderr from crash test.\n"); + fflush(stdout); + fflush(stderr); +#ifdef CRASH_USING_ABORT + abort(); +#else + assert(invalidAddress); /* Quiet Clang scan-build. */ + /* Provoke deliberate crash by writing to the invalid address. */ + *invalidAddress = 0; +#endif + fprintf(stdout, "Output after crash on stdout from crash test.\n"); + fprintf(stderr, "Output after crash on stderr from crash test.\n"); + return 0; +} + +static int test5(int argc, const char* argv[]) +{ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "4"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before recursive test.\n"); + fprintf(stderr, "Output on stderr before recursive test.\n"); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, kwsysProcess_State_Exception, +#ifdef CRASH_USING_ABORT + kwsysProcess_Exception_Other, +#else + kwsysProcess_Exception_Fault, +#endif + 1, 1, 1, 0, 15, 0, 1, 0, 0, 0); + fprintf(stdout, "Output on stdout after recursive test.\n"); + fprintf(stderr, "Output on stderr after recursive test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +#define TEST6_SIZE (4096 * 2) +static void test6(int argc, const char* argv[]) +{ + int i; + char runaway[TEST6_SIZE + 1]; + (void)argc; + (void)argv; + for (i = 0; i < TEST6_SIZE; ++i) { + runaway[i] = '.'; + } + runaway[TEST6_SIZE] = '\n'; + + /* Generate huge amounts of output to test killing. */ + for (;;) { + fwrite(runaway, 1, TEST6_SIZE + 1, stdout); + fflush(stdout); + } +} + +/* Define MINPOLL to be one more than the number of times output is + written. Define MAXPOLL to be the largest number of times a loop + delaying 1/10th of a second should ever have to poll. */ +#define MINPOLL 5 +#define MAXPOLL 20 +static int test7(int argc, const char* argv[]) +{ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout before sleep.\n"); + fprintf(stderr, "Output on stderr before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* Sleep for 1 second. */ + testProcess_sleep(1); + fprintf(stdout, "Output on stdout after sleep.\n"); + fprintf(stderr, "Output on stderr after sleep.\n"); + fflush(stdout); + fflush(stderr); + return 0; +} + +static int test8(int argc, const char* argv[]) +{ + /* Create a disowned grandchild to test handling of processes + that exit before their children. */ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "108"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before grandchild test.\n"); + fprintf(stderr, "Output on stderr before grandchild test.\n"); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None, + 1, 1, 1, 0, 10, 0, 1, 1, 0, 0); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +static int test8_grandchild(int argc, const char* argv[]) +{ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* TODO: Instead of closing pipes here leave them open to make sure + the grandparent can stop listening when the parent exits. This + part of the test cannot be enabled until the feature is + implemented. */ + fclose(stdout); + fclose(stderr); + testProcess_sleep(15); + return 0; +} + +static int test9(int argc, const char* argv[]) +{ + /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this + process. Here, we start a child process that sleeps for a long time + while ignoring signals. The test is successful if this process waits + for the child to return before exiting from the Ctrl+C handler. + + WARNING: This test will falsely pass if the share parameter of runChild + was set to 0 when invoking the test9 process. */ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "109"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before grandchild test.\n"); + fprintf(stderr, "Output on stderr before grandchild test.\n"); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, kwsysProcess_State_Exited, kwsysProcess_Exception_None, 0, + 1, 1, 0, 30, 0, 1, 0, 0, 0); + /* This sleep will avoid a race condition between this function exiting + normally and our Ctrl+C handler exiting abnormally after the process + exits. */ + testProcess_sleep(1); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +#if defined(_WIN32) +static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType) +{ + /* Ignore all Ctrl+C/Break signals. We must use an actual handler function + instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also + ignore Ctrl+Break in addition to Ctrl+C. */ + (void)dwCtrlType; + return TRUE; +} +#endif + +static int test9_grandchild(int argc, const char* argv[]) +{ + /* The grandchild just sleeps for a few seconds while ignoring signals. */ + (void)argc; + (void)argv; +#if defined(_WIN32) + if (!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE)) { + return 1; + } +#else + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGINT, &sa, 0) < 0) { + return 1; + } +#endif + fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* Sleep for 9 seconds. */ + testProcess_sleep(9); + fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); + fflush(stdout); + fflush(stderr); + return 0; +} + +static int test10(int argc, const char* argv[]) +{ + /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this + process. Here, we start a child process that sleeps for a long time and + processes signals normally. However, this grandchild is created in a new + process group - ensuring that Ctrl+C we receive is sent to our process + groups. We make sure it exits anyway. */ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "110"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before grandchild test.\n"); + fprintf(stderr, "Output on stderr before grandchild test.\n"); + fflush(stdout); + fflush(stderr); + r = + runChild(cmd, kwsysProcess_State_Exception, + kwsysProcess_Exception_Interrupt, 0, 1, 1, 0, 30, 0, 1, 0, 1, 0); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +static int test10_grandchild(int argc, const char* argv[]) +{ + /* The grandchild just sleeps for a few seconds and handles signals. */ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* Sleep for 6 seconds. */ + testProcess_sleep(6); + fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); + fflush(stdout); + fflush(stderr); + return 0; +} + +static int runChild2(kwsysProcess* kp, const char* cmd[], int state, + int exception, int value, int share, int output, + int delay, double timeout, int poll, int disown, + int createNewGroup, unsigned int interruptDelay) +{ + int result = 0; + char* data = 0; + int length = 0; + double userTimeout = 0; + double* pUserTimeout = 0; + kwsysProcess_SetCommand(kp, cmd); + if (timeout >= 0) { + kwsysProcess_SetTimeout(kp, timeout); + } + if (share) { + kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1); + kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1); + } + if (disown) { + kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1); + } + if (createNewGroup) { + kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1); + } + kwsysProcess_Execute(kp); + + if (poll) { + pUserTimeout = &userTimeout; + } + + if (interruptDelay) { + testProcess_sleep(interruptDelay); + kwsysProcess_Interrupt(kp); + } + + if (!share && !disown) { + int p; + while ((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout))) { + if (output) { + if (poll && p == kwsysProcess_Pipe_Timeout) { + fprintf(stdout, "WaitForData timeout reached.\n"); + fflush(stdout); + + /* Count the number of times we polled without getting data. + If it is excessive then kill the child and fail. */ + if (++poll >= MAXPOLL) { + fprintf(stdout, "Poll count reached limit %d.\n", MAXPOLL); + kwsysProcess_Kill(kp); + } + } else { + fwrite(data, 1, (size_t)length, stdout); + fflush(stdout); + } + } + if (poll) { + /* Delay to avoid busy loop during polling. */ + testProcess_usleep(100000); + } + if (delay) { +/* Purposely sleeping only on Win32 to let pipe fill up. */ +#if defined(_WIN32) + testProcess_usleep(100000); +#endif + } + } + } + + if (disown) { + kwsysProcess_Disown(kp); + } else { + kwsysProcess_WaitForExit(kp, 0); + } + + switch (kwsysProcess_GetState(kp)) { + case kwsysProcess_State_Starting: + printf("No process has been executed.\n"); + break; + case kwsysProcess_State_Executing: + printf("The process is still executing.\n"); + break; + case kwsysProcess_State_Expired: + printf("Subprocess was killed when timeout expired.\n"); + break; + case kwsysProcess_State_Exited: + printf("Subprocess exited with value = %d\n", + kwsysProcess_GetExitValue(kp)); + result = ((exception != kwsysProcess_GetExitException(kp)) || + (value != kwsysProcess_GetExitValue(kp))); + break; + case kwsysProcess_State_Killed: + printf("Subprocess was killed by parent.\n"); + break; + case kwsysProcess_State_Exception: + printf("Subprocess terminated abnormally: %s\n", + kwsysProcess_GetExceptionString(kp)); + result = ((exception != kwsysProcess_GetExitException(kp)) || + (value != kwsysProcess_GetExitValue(kp))); + break; + case kwsysProcess_State_Disowned: + printf("Subprocess was disowned.\n"); + break; + case kwsysProcess_State_Error: + printf("Error in administrating child process: [%s]\n", + kwsysProcess_GetErrorString(kp)); + break; + } + + if (result) { + if (exception != kwsysProcess_GetExitException(kp)) { + fprintf(stderr, + "Mismatch in exit exception. " + "Should have been %d, was %d.\n", + exception, kwsysProcess_GetExitException(kp)); + } + if (value != kwsysProcess_GetExitValue(kp)) { + fprintf(stderr, + "Mismatch in exit value. " + "Should have been %d, was %d.\n", + value, kwsysProcess_GetExitValue(kp)); + } + } + + if (kwsysProcess_GetState(kp) != state) { + fprintf(stderr, + "Mismatch in state. " + "Should have been %d, was %d.\n", + state, kwsysProcess_GetState(kp)); + result = 1; + } + + /* We should have polled more times than there were data if polling + was enabled. */ + if (poll && poll < MINPOLL) { + fprintf(stderr, "Poll count is %d, which is less than %d.\n", poll, + MINPOLL); + result = 1; + } + + return result; +} + +/** + * Runs a child process and blocks until it returns. Arguments as follows: + * + * cmd = Command line to run. + * state = Expected return value of kwsysProcess_GetState after exit. + * exception = Expected return value of kwsysProcess_GetExitException. + * value = Expected return value of kwsysProcess_GetExitValue. + * share = Whether to share stdout/stderr child pipes with our pipes + * by way of kwsysProcess_SetPipeShared. If false, new pipes + * are created. + * output = If !share && !disown, whether to write the child's stdout + * and stderr output to our stdout. + * delay = If !share && !disown, adds an additional short delay to + * the pipe loop to allow the pipes to fill up; Windows only. + * timeout = Non-zero to sets a timeout in seconds via + * kwsysProcess_SetTimeout. + * poll = If !share && !disown, we count the number of 0.1 second + * intervals where the child pipes had no new data. We fail + * if not in the bounds of MINPOLL/MAXPOLL. + * repeat = Number of times to run the process. + * disown = If set, the process is disowned. + * createNewGroup = If set, the process is created in a new process group. + * interruptDelay = If non-zero, number of seconds to delay before + * interrupting the process. Note that this delay will occur + * BEFORE any reading/polling of pipes occurs and before any + * detachment occurs. + */ +int runChild(const char* cmd[], int state, int exception, int value, int share, + int output, int delay, double timeout, int poll, int repeat, + int disown, int createNewGroup, unsigned int interruptDelay) +{ + int result = 1; + kwsysProcess* kp = kwsysProcess_New(); + if (!kp) { + fprintf(stderr, "kwsysProcess_New returned NULL!\n"); + return 1; + } + while (repeat-- > 0) { + result = runChild2(kp, cmd, state, exception, value, share, output, delay, + timeout, poll, disown, createNewGroup, interruptDelay); + if (result) { + break; + } + } + kwsysProcess_Delete(kp); + return result; +} + +int main(int argc, const char* argv[]) +{ + int n = 0; + +#ifdef _WIN32 + int i; + char new_args[10][_MAX_PATH]; + LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &argc); + for (i = 0; i < argc; i++) { + kwsysEncoding_wcstombs(new_args[i], w_av[i], _MAX_PATH); + argv[i] = new_args[i]; + } + LocalFree(w_av); +#endif + +#if 0 + { + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + DuplicateHandle(GetCurrentProcess(), out, + GetCurrentProcess(), &out, 0, FALSE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + SetStdHandle(STD_OUTPUT_HANDLE, out); + } + { + HANDLE out = GetStdHandle(STD_ERROR_HANDLE); + DuplicateHandle(GetCurrentProcess(), out, + GetCurrentProcess(), &out, 0, FALSE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + SetStdHandle(STD_ERROR_HANDLE, out); + } +#endif + if (argc == 2) { + n = atoi(argv[1]); + } else if (argc == 3 && strcmp(argv[1], "run") == 0) { + n = atoi(argv[2]); + } + /* Check arguments. */ + if (((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3) { + /* This is the child process for a requested test number. */ + switch (n) { + case 1: + return test1(argc, argv); + case 2: + return test2(argc, argv); + case 3: + return test3(argc, argv); + case 4: + return test4(argc, argv); + case 5: + return test5(argc, argv); + case 6: + test6(argc, argv); + return 0; + case 7: + return test7(argc, argv); + case 8: + return test8(argc, argv); + case 9: + return test9(argc, argv); + case 10: + return test10(argc, argv); + case 108: + return test8_grandchild(argc, argv); + case 109: + return test9_grandchild(argc, argv); + case 110: + return test10_grandchild(argc, argv); + } + fprintf(stderr, "Invalid test number %d.\n", n); + return 1; + } + if (n >= 1 && n <= 10) { + /* This is the parent process for a requested test number. */ + int states[10] = { + kwsysProcess_State_Exited, kwsysProcess_State_Exited, + kwsysProcess_State_Expired, kwsysProcess_State_Exception, + kwsysProcess_State_Exited, kwsysProcess_State_Expired, + kwsysProcess_State_Exited, kwsysProcess_State_Exited, + kwsysProcess_State_Expired, /* Ctrl+C handler test */ + kwsysProcess_State_Exception /* Process group test */ + }; + int exceptions[10] = { + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, +#ifdef CRASH_USING_ABORT + kwsysProcess_Exception_Other, +#else + kwsysProcess_Exception_Fault, +#endif + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, kwsysProcess_Exception_Interrupt + }; + int values[10] = { 0, 123, 1, 1, 0, 0, 0, 0, 1, 1 }; + int shares[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; + int outputs[10] = { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }; + int delays[10] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; + double timeouts[10] = { 10, 10, 10, 30, 30, 10, -1, 10, 6, 4 }; + int polls[10] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; + int repeat[10] = { 257, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + int createNewGroups[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; + unsigned int interruptDelays[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 2 }; + int r; + const char* cmd[4]; +#ifdef _WIN32 + char* argv0 = 0; +#endif + char* test1IterationsStr = getenv("KWSYS_TEST_PROCESS_1_COUNT"); + if (test1IterationsStr) { + long int test1Iterations = strtol(test1IterationsStr, 0, 10); + if (test1Iterations > 10 && test1Iterations != LONG_MAX) { + repeat[0] = (int)test1Iterations; + } + } +#ifdef _WIN32 + if (n == 0 && (argv0 = strdup(argv[0]))) { + /* Try converting to forward slashes to see if it works. */ + char* c; + for (c = argv0; *c; ++c) { + if (*c == '\\') { + *c = '/'; + } + } + cmd[0] = argv0; + } else { + cmd[0] = argv[0]; + } +#else + cmd[0] = argv[0]; +#endif + cmd[1] = "run"; + cmd[2] = argv[1]; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before test %d.\n", n); + fprintf(stderr, "Output on stderr before test %d.\n", n); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, states[n - 1], exceptions[n - 1], values[n - 1], + shares[n - 1], outputs[n - 1], delays[n - 1], timeouts[n - 1], + polls[n - 1], repeat[n - 1], 0, createNewGroups[n - 1], + interruptDelays[n - 1]); + fprintf(stdout, "Output on stdout after test %d.\n", n); + fprintf(stderr, "Output on stderr after test %d.\n", n); + fflush(stdout); + fflush(stderr); +#if defined(_WIN32) + free(argv0); +#endif + return r; + } + if (argc > 2 && strcmp(argv[1], "0") == 0) { + /* This is the special debugging test to run a given command + line. */ + const char** cmd = argv + 2; + int state = kwsysProcess_State_Exited; + int exception = kwsysProcess_Exception_None; + int value = 0; + double timeout = 0; + int r = + runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0, 0, 0); + return r; + } + /* Improper usage. */ + fprintf(stdout, "Usage: %s \n", argv[0]); + return 1; +} diff --git a/testSharedForward.c.in b/testSharedForward.c.in new file mode 100644 index 0000000000..b3eb413828 --- /dev/null +++ b/testSharedForward.c.in @@ -0,0 +1,27 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#if defined(CMAKE_INTDIR) +# define CONFIG_DIR_PRE CMAKE_INTDIR "/" +# define CONFIG_DIR_POST "/" CMAKE_INTDIR +#else +# define CONFIG_DIR_PRE "" +# define CONFIG_DIR_POST "" +#endif +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "@EXEC_DIR@" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL 0 +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD \ + CONFIG_DIR_PRE "@KWSYS_NAMESPACE@TestProcess" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL \ + "@KWSYS_NAMESPACE@TestProcess" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd" +#if defined(CMAKE_INTDIR) +# define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR +#endif +#include <@KWSYS_NAMESPACE@/SharedForward.h> +int main(int argc, char** argv) +{ + return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv); +} diff --git a/testSystemInformation.cxx b/testSystemInformation.cxx new file mode 100644 index 0000000000..4f0c522e4f --- /dev/null +++ b/testSystemInformation.cxx @@ -0,0 +1,90 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(SystemInformation.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "SystemInformation.hxx.in" +#endif + +#include + +#define printMethod(info, m) std::cout << #m << ": " << info.m() << "\n" + +#define printMethod2(info, m, unit) \ + std::cout << #m << ": " << info.m() << " " << unit << "\n" + +#define printMethod3(info, m, unit) \ + std::cout << #m << ": " << info.m << " " << unit << "\n" + +int testSystemInformation(int, char* []) +{ + std::cout << "CTEST_FULL_OUTPUT\n"; // avoid truncation + + kwsys::SystemInformation info; + info.RunCPUCheck(); + info.RunOSCheck(); + info.RunMemoryCheck(); + printMethod(info, GetOSName); + printMethod(info, GetOSIsLinux); + printMethod(info, GetOSIsApple); + printMethod(info, GetOSIsWindows); + printMethod(info, GetHostname); + printMethod(info, GetFullyQualifiedDomainName); + printMethod(info, GetOSRelease); + printMethod(info, GetOSVersion); + printMethod(info, GetOSPlatform); + printMethod(info, Is64Bits); + printMethod(info, GetVendorString); + printMethod(info, GetVendorID); + printMethod(info, GetTypeID); + printMethod(info, GetFamilyID); + printMethod(info, GetModelID); + printMethod(info, GetExtendedProcessorName); + printMethod(info, GetSteppingCode); + printMethod(info, GetProcessorSerialNumber); + printMethod2(info, GetProcessorCacheSize, "KB"); + printMethod(info, GetLogicalProcessorsPerPhysical); + printMethod2(info, GetProcessorClockFrequency, "MHz"); + printMethod(info, GetNumberOfLogicalCPU); + printMethod(info, GetNumberOfPhysicalCPU); + printMethod(info, DoesCPUSupportCPUID); + printMethod(info, GetProcessorAPICID); + printMethod2(info, GetTotalVirtualMemory, "MB"); + printMethod2(info, GetAvailableVirtualMemory, "MB"); + printMethod2(info, GetTotalPhysicalMemory, "MB"); + printMethod2(info, GetAvailablePhysicalMemory, "MB"); + printMethod3(info, GetHostMemoryTotal(), "KiB"); + printMethod3(info, GetHostMemoryAvailable("KWSHL"), "KiB"); + printMethod3(info, GetProcMemoryAvailable("KWSHL", "KWSPL"), "KiB"); + printMethod3(info, GetHostMemoryUsed(), "KiB"); + printMethod3(info, GetProcMemoryUsed(), "KiB"); + printMethod(info, GetLoadAverage); + + for (long int i = 0; i <= 31; i++) { + if (info.DoesCPUSupportFeature(static_cast(1) << i)) { + std::cout << "CPU feature " << i << "\n"; + } + } + + /* test stack trace + */ + std::cout << "Program Stack:" << std::endl + << kwsys::SystemInformation::GetProgramStack(0, 0) << std::endl + << std::endl; + + /* test segv handler + info.SetStackTraceOnError(1); + double *d = (double*)100; + *d=0; + */ + + /* test abort handler + info.SetStackTraceOnError(1); + abort(); + */ + + return 0; +} diff --git a/testSystemTools.bin b/testSystemTools.bin new file mode 100644 index 0000000000000000000000000000000000000000..961a4043b9b2785351ab26a33cfcb1f366c1391b GIT binary patch literal 766 zcmbV~J8r`;5JX3D078KQr%G#;xrK8icPgzTq*cc{r`QAV5H3@?bYXZsLq;FVX_BRe z%g5!cJ`hlGG|ej%-%r3B^E=g0A5?{B&Opc7@6oZyO4pUdnM;@%vkIOsxNAjmXiL+d z<7 zAIM?AiVDY~%?XgU=c3&OkPg?P^8282@1&KxNx}UnZQM`N*8ME)+%M9>{YuT^22-rR A-v9sr literal 0 HcmV?d00001 diff --git a/testSystemTools.cxx b/testSystemTools.cxx new file mode 100644 index 0000000000..cfa420df49 --- /dev/null +++ b/testSystemTools.cxx @@ -0,0 +1,1233 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +#if defined(_MSC_VER) +# pragma warning(disable : 4786) +#endif + +#include KWSYS_HEADER(FStream.hxx) +#include KWSYS_HEADER(SystemTools.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "FStream.hxx.in" +# include "SystemTools.hxx.in" +#endif + +// Include with <> instead of "" to avoid getting any in-source copy +// left on disk. +#include + +#include /* free */ +#include /* strcmp */ +#include +#include +#if defined(_WIN32) && !defined(__CYGWIN__) +# include /* _umask (MSVC) */ +# ifdef _MSC_VER +# define umask _umask +# endif +#endif +#include /* umask (POSIX), _S_I* constants (Windows) */ +// Visual C++ does not define mode_t. +#if defined(_MSC_VER) +typedef unsigned short mode_t; +#endif + +static const char* toUnixPaths[][2] = { + { "/usr/local/bin/passwd", "/usr/local/bin/passwd" }, + { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" }, + { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, + { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" }, + { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" }, + { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, + { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" }, + { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" }, + { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, + { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" }, + { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" }, + { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, + { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" }, + { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" }, + { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo/ cal/bin/pa/ sswd" }, + { nullptr, nullptr } +}; + +static bool CheckConvertToUnixSlashes(std::string const& input, + std::string const& output) +{ + std::string result = input; + kwsys::SystemTools::ConvertToUnixSlashes(result); + if (result != output) { + std::cerr << "Problem with ConvertToUnixSlashes - input: " << input + << " output: " << result << " expected: " << output << std::endl; + return false; + } + return true; +} + +static const char* checkEscapeChars[][4] = { + { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2" }, + { " {} ", "{}", "#", " #{#} " }, + { nullptr, nullptr, nullptr, nullptr } +}; + +static bool CheckEscapeChars(std::string const& input, + const char* chars_to_escape, char escape_char, + std::string const& output) +{ + std::string result = kwsys::SystemTools::EscapeChars( + input.c_str(), chars_to_escape, escape_char); + if (result != output) { + std::cerr << "Problem with CheckEscapeChars - input: " << input + << " output: " << result << " expected: " << output << std::endl; + return false; + } + return true; +} + +static bool CheckFileOperations() +{ + bool res = true; + const std::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR + "/testSystemToolsNonExistingFile"); + const std::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR "/."); + const std::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR + "/testSystemTools.bin"); + const std::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR + "/testSystemTools.cxx"); + const std::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR + "/testSystemToolsNewDir"); + const std::string testNewFile(testNewDir + "/testNewFile.txt"); + + if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) != + kwsys::SystemTools::FileTypeUnknown) { + std::cerr << "Problem with DetectFileType - failed to detect type of: " + << testNonExistingFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) != + kwsys::SystemTools::FileTypeUnknown) { + std::cerr << "Problem with DetectFileType - failed to detect type of: " + << testDotFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) != + kwsys::SystemTools::FileTypeBinary) { + std::cerr << "Problem with DetectFileType - failed to detect type of: " + << testBinFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) != + kwsys::SystemTools::FileTypeText) { + std::cerr << "Problem with DetectFileType - failed to detect type of: " + << testTxtFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::FileLength(testBinFile) != 766) { + std::cerr << "Problem with FileLength - incorrect length for: " + << testBinFile << std::endl; + res = false; + } + + kwsys::SystemTools::Stat_t buf; + if (kwsys::SystemTools::Stat(testTxtFile.c_str(), &buf) != 0) { + std::cerr << "Problem with Stat - unable to stat text file: " + << testTxtFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::Stat(testBinFile, &buf) != 0) { + std::cerr << "Problem with Stat - unable to stat bin file: " << testBinFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::MakeDirectory(testNewDir)) { + std::cerr << "Problem with MakeDirectory for: " << testNewDir << std::endl; + res = false; + } + // calling it again should just return true + if (!kwsys::SystemTools::MakeDirectory(testNewDir)) { + std::cerr << "Problem with second call to MakeDirectory for: " + << testNewDir << std::endl; + res = false; + } + // calling with 0 pointer should return false + if (kwsys::SystemTools::MakeDirectory(nullptr)) { + std::cerr << "Problem with MakeDirectory(0)" << std::endl; + res = false; + } + // calling with an empty string should return false + if (kwsys::SystemTools::MakeDirectory(std::string())) { + std::cerr << "Problem with MakeDirectory(std::string())" << std::endl; + res = false; + } + // check existence + if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { + std::cerr << "Problem with FileExists as C string and not file for: " + << testNewDir << std::endl; + res = false; + } + // check existence + if (!kwsys::SystemTools::PathExists(testNewDir)) { + std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; + res = false; + } + // remove it + if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { + std::cerr << "Problem with RemoveADirectory for: " << testNewDir + << std::endl; + res = false; + } + // check existence + if (kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { + std::cerr << "After RemoveADirectory: " + << "Problem with FileExists as C string and not file for: " + << testNewDir << std::endl; + res = false; + } + // check existence + if (kwsys::SystemTools::PathExists(testNewDir)) { + std::cerr << "After RemoveADirectory: " + << "Problem with PathExists for: " << testNewDir << std::endl; + res = false; + } + // create it using the char* version + if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str())) { + std::cerr << "Problem with second call to MakeDirectory as C string for: " + << testNewDir << std::endl; + res = false; + } + + if (!kwsys::SystemTools::Touch(testNewFile, true)) { + std::cerr << "Problem with Touch for: " << testNewFile << std::endl; + res = false; + } + // calling MakeDirectory with something that is no file should fail + if (kwsys::SystemTools::MakeDirectory(testNewFile)) { + std::cerr << "Problem with to MakeDirectory for: " << testNewFile + << std::endl; + res = false; + } + + // calling with 0 pointer should return false + if (kwsys::SystemTools::FileExists(nullptr)) { + std::cerr << "Problem with FileExists(0)" << std::endl; + res = false; + } + if (kwsys::SystemTools::FileExists(nullptr, true)) { + std::cerr << "Problem with FileExists(0) as file" << std::endl; + res = false; + } + // calling with an empty string should return false + if (kwsys::SystemTools::FileExists(std::string())) { + std::cerr << "Problem with FileExists(std::string())" << std::endl; + res = false; + } + // FileExists(x, true) should return false on a directory + if (kwsys::SystemTools::FileExists(testNewDir, true)) { + std::cerr << "Problem with FileExists as file for: " << testNewDir + << std::endl; + res = false; + } + if (kwsys::SystemTools::FileExists(testNewDir.c_str(), true)) { + std::cerr << "Problem with FileExists as C string and file for: " + << testNewDir << std::endl; + res = false; + } + // FileExists(x, false) should return true even on a directory + if (!kwsys::SystemTools::FileExists(testNewDir, false)) { + std::cerr << "Problem with FileExists as not file for: " << testNewDir + << std::endl; + res = false; + } + if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { + std::cerr << "Problem with FileExists as C string and not file for: " + << testNewDir << std::endl; + res = false; + } + // should work, was created as new file before + if (!kwsys::SystemTools::FileExists(testNewFile)) { + std::cerr << "Problem with FileExists for: " << testNewFile << std::endl; + res = false; + } + if (!kwsys::SystemTools::FileExists(testNewFile.c_str())) { + std::cerr << "Problem with FileExists as C string for: " << testNewFile + << std::endl; + res = false; + } + if (!kwsys::SystemTools::FileExists(testNewFile, true)) { + std::cerr << "Problem with FileExists as file for: " << testNewFile + << std::endl; + res = false; + } + if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true)) { + std::cerr << "Problem with FileExists as C string and file for: " + << testNewFile << std::endl; + res = false; + } + + // calling with an empty string should return false + if (kwsys::SystemTools::PathExists(std::string())) { + std::cerr << "Problem with PathExists(std::string())" << std::endl; + res = false; + } + // PathExists(x) should return true on a directory + if (!kwsys::SystemTools::PathExists(testNewDir)) { + std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; + res = false; + } + // should work, was created as new file before + if (!kwsys::SystemTools::PathExists(testNewFile)) { + std::cerr << "Problem with PathExists for: " << testNewFile << std::endl; + res = false; + } + +// Reset umask +#if defined(_WIN32) && !defined(__CYGWIN__) + // NOTE: Windows doesn't support toggling _S_IREAD. + mode_t fullMask = _S_IWRITE; +#else + // On a normal POSIX platform, we can toggle all permissions. + mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO; +#endif + mode_t orig_umask = umask(fullMask); + + // Test file permissions without umask + mode_t origPerm, thisPerm; + if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) { + std::cerr << "Problem with GetPermissions (1) for: " << testNewFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) { + std::cerr << "Problem with SetPermissions (1) for: " << testNewFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { + std::cerr << "Problem with GetPermissions (2) for: " << testNewFile + << std::endl; + res = false; + } + + if ((thisPerm & fullMask) != 0) { + std::cerr << "SetPermissions failed to set permissions (1) for: " + << testNewFile << ": actual = " << thisPerm + << "; expected = " << 0 << std::endl; + res = false; + } + + // While we're at it, check proper TestFileAccess functionality. + bool do_write_test = true; +#if defined(__linux__) + // If we are running as root on linux ignore this check, as + // root can always write to files + do_write_test = (getuid() != 0); +#endif + if (do_write_test && + kwsys::SystemTools::TestFileAccess(testNewFile, + kwsys::TEST_FILE_WRITE)) { + std::cerr + << "TestFileAccess incorrectly indicated that this is a writable file:" + << testNewFile << std::endl; + res = false; + } + + if (!kwsys::SystemTools::TestFileAccess(testNewFile, kwsys::TEST_FILE_OK)) { + std::cerr + << "TestFileAccess incorrectly indicated that this file does not exist:" + << testNewFile << std::endl; + res = false; + } + + // Test restoring/setting full permissions. + if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask)) { + std::cerr << "Problem with SetPermissions (2) for: " << testNewFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { + std::cerr << "Problem with GetPermissions (3) for: " << testNewFile + << std::endl; + res = false; + } + + if ((thisPerm & fullMask) != fullMask) { + std::cerr << "SetPermissions failed to set permissions (2) for: " + << testNewFile << ": actual = " << thisPerm + << "; expected = " << fullMask << std::endl; + res = false; + } + + // Test setting file permissions while honoring umask + if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) { + std::cerr << "Problem with SetPermissions (3) for: " << testNewFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { + std::cerr << "Problem with GetPermissions (4) for: " << testNewFile + << std::endl; + res = false; + } + + if ((thisPerm & fullMask) != 0) { + std::cerr << "SetPermissions failed to honor umask for: " << testNewFile + << ": actual = " << thisPerm << "; expected = " << 0 + << std::endl; + res = false; + } + + // Restore umask + umask(orig_umask); + + // Restore file permissions + if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm)) { + std::cerr << "Problem with SetPermissions (4) for: " << testNewFile + << std::endl; + res = false; + } + + // Remove the test file + if (!kwsys::SystemTools::RemoveFile(testNewFile)) { + std::cerr << "Problem with RemoveFile: " << testNewFile << std::endl; + res = false; + } + + std::string const testFileMissing(testNewDir + "/testMissingFile.txt"); + if (!kwsys::SystemTools::RemoveFile(testFileMissing)) { + std::string const& msg = kwsys::SystemTools::GetLastSystemError(); + std::cerr << "RemoveFile(\"" << testFileMissing << "\") failed: " << msg + << "\n"; + res = false; + } + + std::string const testFileMissingDir(testNewDir + "/missing/file.txt"); + if (!kwsys::SystemTools::RemoveFile(testFileMissingDir)) { + std::string const& msg = kwsys::SystemTools::GetLastSystemError(); + std::cerr << "RemoveFile(\"" << testFileMissingDir << "\") failed: " << msg + << "\n"; + res = false; + } + +#if !defined(_WIN32) + std::string const testBadSymlink(testNewDir + "/badSymlink.txt"); + std::string const testBadSymlinkTgt(testNewDir + "/missing/symlinkTgt.txt"); + if (!kwsys::SystemTools::CreateSymlink(testBadSymlinkTgt, testBadSymlink)) { + std::cerr << "Problem with CreateSymlink for: " << testBadSymlink << " -> " + << testBadSymlinkTgt << std::endl; + res = false; + } + + if (!kwsys::SystemTools::Touch(testBadSymlink, false)) { + std::cerr << "Problem with Touch (no create) for: " << testBadSymlink + << std::endl; + res = false; + } +#endif + + if (!kwsys::SystemTools::Touch(testNewDir, false)) { + std::cerr << "Problem with Touch (no create) for: " << testNewDir + << std::endl; + res = false; + } + + kwsys::SystemTools::Touch(testNewFile, true); + if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { + std::cerr << "Problem with RemoveADirectory for: " << testNewDir + << std::endl; + res = false; + } + +#ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS + // Perform the same file and directory creation and deletion tests but + // with paths > 256 characters in length. + + const std::string testNewLongDir( + TEST_SYSTEMTOOLS_BINARY_DIR + "/" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "01234567890123"); + const std::string testNewLongFile( + testNewLongDir + + "/" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "0123456789.txt"); + + if (!kwsys::SystemTools::MakeDirectory(testNewLongDir)) { + std::cerr << "Problem with MakeDirectory for: " << testNewLongDir + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true)) { + std::cerr << "Problem with Touch for: " << testNewLongFile << std::endl; + res = false; + } + + if (!kwsys::SystemTools::RemoveFile(testNewLongFile)) { + std::cerr << "Problem with RemoveFile: " << testNewLongFile << std::endl; + res = false; + } + + kwsys::SystemTools::Touch(testNewLongFile.c_str(), true); + if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir)) { + std::cerr << "Problem with RemoveADirectory for: " << testNewLongDir + << std::endl; + res = false; + } +#endif + + return res; +} + +static bool CheckStringOperations() +{ + bool res = true; + + std::string test = "mary had a little lamb."; + if (kwsys::SystemTools::CapitalizedWords(test) != + "Mary Had A Little Lamb.") { + std::cerr << "Problem with CapitalizedWords " << '"' << test << '"' + << std::endl; + res = false; + } + + test = "Mary Had A Little Lamb."; + if (kwsys::SystemTools::UnCapitalizedWords(test) != + "mary had a little lamb.") { + std::cerr << "Problem with UnCapitalizedWords " << '"' << test << '"' + << std::endl; + res = false; + } + + test = "MaryHadTheLittleLamb."; + if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) != + "Mary Had The Little Lamb.") { + std::cerr << "Problem with AddSpaceBetweenCapitalizedWords " << '"' << test + << '"' << std::endl; + res = false; + } + + char* cres = + kwsys::SystemTools::AppendStrings("Mary Had A", " Little Lamb."); + if (strcmp(cres, "Mary Had A Little Lamb.") != 0) { + std::cerr << "Problem with AppendStrings " + << "\"Mary Had A\" \" Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + cres = kwsys::SystemTools::AppendStrings("Mary Had", " A ", "Little Lamb."); + if (strcmp(cres, "Mary Had A Little Lamb.") != 0) { + std::cerr << "Problem with AppendStrings " + << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.", 'a') != 3) { + std::cerr << "Problem with CountChar " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + cres = kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.", "aeiou"); + if (strcmp(cres, "Mry Hd A Lttl Lmb.") != 0) { + std::cerr << "Problem with RemoveChars " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + cres = kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb."); + if (strcmp(cres, "A") != 0) { + std::cerr << "Problem with RemoveCharsButUpperHex " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + char* cres2 = strdup("Mary Had A Little Lamb."); + kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X'); + if (strcmp(cres2, "MXry HXd A LXttlX LXmb.") != 0) { + std::cerr << "Problem with ReplaceChars " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + free(cres2); + + if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.", + "Mary ")) { + std::cerr << "Problem with StringStartsWith " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.", + " Lamb.")) { + std::cerr << "Problem with StringEndsWith " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb."); + if (strcmp(cres, "Mary Had A Little Lamb.") != 0) { + std::cerr << "Problem with DuplicateString " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + test = "Mary Had A Little Lamb."; + if (kwsys::SystemTools::CropString(test, 13) != "Mary ...Lamb.") { + std::cerr << "Problem with CropString " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + std::vector lines; + kwsys::SystemTools::Split("Mary Had A Little Lamb.", lines, ' '); + if (lines[0] != "Mary" || lines[1] != "Had" || lines[2] != "A" || + lines[3] != "Little" || lines[4] != "Lamb.") { + std::cerr << "Problem with Split " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToWindowsOutputPath( + "L://Local Mojo/Hex Power Pack/Iffy Voodoo") != + "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { + std::cerr << "Problem with ConvertToWindowsOutputPath " + << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToWindowsOutputPath( + "//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") != + "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { + std::cerr << "Problem with ConvertToWindowsOutputPath " + << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\"" + << std::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToUnixOutputPath( + "//Local Mojo/Hex Power Pack/Iffy Voodoo") != + "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo") { + std::cerr << "Problem with ConvertToUnixOutputPath " + << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; + res = false; + } + + return res; +} + +static bool CheckPutEnv(const std::string& env, const char* name, + const char* value) +{ + if (!kwsys::SystemTools::PutEnv(env)) { + std::cerr << "PutEnv(\"" << env << "\") failed!" << std::endl; + return false; + } + std::string v = "(null)"; + kwsys::SystemTools::GetEnv(name, v); + if (v != value) { + std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not \"" + << value << "\"!" << std::endl; + return false; + } + return true; +} + +static bool CheckUnPutEnv(const char* env, const char* name) +{ + if (!kwsys::SystemTools::UnPutEnv(env)) { + std::cerr << "UnPutEnv(\"" << env << "\") failed!" << std::endl; + return false; + } + std::string v; + if (kwsys::SystemTools::GetEnv(name, v)) { + std::cerr << "GetEnv(\"" << name << "\") returned \"" << v + << "\", not (null)!" << std::endl; + return false; + } + return true; +} + +static bool CheckEnvironmentOperations() +{ + bool res = true; + res &= CheckPutEnv("A=B", "A", "B"); + res &= CheckPutEnv("B=C", "B", "C"); + res &= CheckPutEnv("C=D", "C", "D"); + res &= CheckPutEnv("D=E", "D", "E"); + res &= CheckUnPutEnv("A", "A"); + res &= CheckUnPutEnv("B=", "B"); + res &= CheckUnPutEnv("C=D", "C"); + /* Leave "D=E" in environment so a memory checker can test for leaks. */ + return res; +} + +static bool CheckRelativePath(const std::string& local, + const std::string& remote, + const std::string& expected) +{ + std::string result = kwsys::SystemTools::RelativePath(local, remote); + if (!kwsys::SystemTools::ComparePath(expected, result)) { + std::cerr << "RelativePath(" << local << ", " << remote << ") yielded " + << result << " instead of " << expected << std::endl; + return false; + } + return true; +} + +static bool CheckRelativePaths() +{ + bool res = true; + res &= CheckRelativePath("/usr/share", "/bin/bash", "../../bin/bash"); + res &= CheckRelativePath("/usr/./share/", "/bin/bash", "../../bin/bash"); + res &= CheckRelativePath("/usr//share/", "/bin/bash", "../../bin/bash"); + res &= + CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash"); + res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin"); + return res; +} + +static bool CheckCollapsePath(const std::string& path, + const std::string& expected, + const char* base = nullptr) +{ + std::string result = kwsys::SystemTools::CollapseFullPath(path, base); + if (!kwsys::SystemTools::ComparePath(expected, result)) { + std::cerr << "CollapseFullPath(" << path << ") yielded " << result + << " instead of " << expected << std::endl; + return false; + } + return true; +} + +static bool CheckCollapsePath() +{ + bool res = true; + res &= CheckCollapsePath("/usr/share/*", "/usr/share/*"); + res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*"); + res &= CheckCollapsePath("/usr/share/../lib", "/usr/lib"); + res &= CheckCollapsePath("/usr/share/./lib", "/usr/share/lib"); + res &= CheckCollapsePath("/usr/share/../../lib", "/lib"); + res &= CheckCollapsePath("/usr/share/.././../lib", "/lib"); + res &= CheckCollapsePath("/../lib", "/lib"); + res &= CheckCollapsePath("/../lib/", "/lib"); + res &= CheckCollapsePath("/", "/"); + res &= CheckCollapsePath("C:/", "C:/"); + res &= CheckCollapsePath("C:/../", "C:/"); + res &= CheckCollapsePath("C:/../../", "C:/"); + res &= CheckCollapsePath("../b", "../../b", "../"); + res &= CheckCollapsePath("../a/../b", "../b", "../rel"); + res &= CheckCollapsePath("a/../b", "../rel/b", "../rel"); + return res; +} + +static std::string StringVectorToString(const std::vector& vec) +{ + std::stringstream ss; + ss << "vector("; + for (auto i = vec.begin(); i != vec.end(); ++i) { + if (i != vec.begin()) { + ss << ", "; + } + ss << *i; + } + ss << ")"; + return ss.str(); +} + +static bool CheckGetPath() +{ + const char* envName = "S"; +#ifdef _WIN32 + const char* envValue = "C:\\Somewhere\\something;D:\\Temp"; +#else + const char* envValue = "/Somewhere/something:/tmp"; +#endif + const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]"; + + std::vector originalPaths; + originalPaths.emplace_back(registryPath); + + std::vector expectedPaths; + expectedPaths.emplace_back(registryPath); +#ifdef _WIN32 + expectedPaths.push_back("C:/Somewhere/something"); + expectedPaths.push_back("D:/Temp"); +#else + expectedPaths.emplace_back("/Somewhere/something"); + expectedPaths.emplace_back("/tmp"); +#endif + + bool res = true; + res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue); + + std::vector paths = originalPaths; + kwsys::SystemTools::GetPath(paths, envName); + + if (paths != expectedPaths) { + std::cerr << "GetPath(" << StringVectorToString(originalPaths) << ", " + << envName << ") yielded " << StringVectorToString(paths) + << " instead of " << StringVectorToString(expectedPaths) + << std::endl; + res = false; + } + + res &= CheckUnPutEnv(envName, envName); + return res; +} + +static bool CheckGetFilenameName() +{ + const char* windowsFilepath = "C:\\somewhere\\something"; + const char* unixFilepath = "/somewhere/something"; + +#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + std::string expectedWindowsFilename = "something"; +#else + std::string expectedWindowsFilename = "C:\\somewhere\\something"; +#endif + std::string expectedUnixFilename = "something"; + + bool res = true; + std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath); + if (filename != expectedWindowsFilename) { + std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded " + << filename << " instead of " << expectedWindowsFilename + << std::endl; + res = false; + } + + filename = kwsys::SystemTools::GetFilenameName(unixFilepath); + if (filename != expectedUnixFilename) { + std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename + << " instead of " << expectedUnixFilename << std::endl; + res = false; + } + return res; +} + +static bool CheckFind() +{ + bool res = true; + const std::string testFindFileName("testFindFile.txt"); + const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/" + + testFindFileName); + + if (!kwsys::SystemTools::Touch(testFindFile, true)) { + std::cerr << "Problem with Touch for: " << testFindFile << std::endl; + // abort here as the existence of the file only makes the test meaningful + return false; + } + + std::vector searchPaths; + searchPaths.emplace_back(TEST_SYSTEMTOOLS_BINARY_DIR); + if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true) + .empty()) { + std::cerr << "Problem with FindFile without system paths for: " + << testFindFileName << std::endl; + res = false; + } + if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, false) + .empty()) { + std::cerr << "Problem with FindFile with system paths for: " + << testFindFileName << std::endl; + res = false; + } + + return res; +} + +static bool CheckIsSubDirectory() +{ + bool res = true; + + if (kwsys::SystemTools::IsSubDirectory("/foo", "/") == false) { + std::cerr << "Problem with IsSubDirectory (root - unix): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("c:/foo", "c:/") == false) { + std::cerr << "Problem with IsSubDirectory (root - dos): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo/bar", "/foo") == false) { + std::cerr << "Problem with IsSubDirectory (deep): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (identity): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/fooo", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (substring): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo/", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (prepended slash): " + << std::endl; + res = false; + } + + return res; +} + +static bool CheckGetLineFromStream() +{ + const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR + "/README.rst"); + + kwsys::ifstream file(fileWithFiveCharsOnFirstLine.c_str(), std::ios::in); + + if (!file) { + std::cerr << "Problem opening: " << fileWithFiveCharsOnFirstLine + << std::endl; + return false; + } + + std::string line; + bool has_newline = false; + bool result; + + file.seekg(0, std::ios::beg); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || line.size() != 5) { + std::cerr << "First line does not have five characters: " << line.size() + << std::endl; + return false; + } + + file.seekg(0, std::ios::beg); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || line.size() != 5) { + std::cerr << "First line does not have five characters after rewind: " + << line.size() << std::endl; + return false; + } + + bool ret = true; + + for (size_t size = 1; size <= 5; ++size) { + file.seekg(0, std::ios::beg); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, + static_cast(size)); + if (!result || line.size() != size) { + std::cerr << "Should have read " << size << " characters but got " + << line.size() << std::endl; + ret = false; + } + } + + return ret; +} + +static bool CheckGetLineFromStreamLongLine() +{ + const std::string fileWithLongLine("longlines.txt"); + std::string firstLine, secondLine; + // First line: large buffer, containing a carriage return for some reason. + firstLine.assign(2050, ' '); + firstLine += "\rfirst"; + secondLine.assign(2050, 'y'); + secondLine += "second"; + + // Create file with long lines. + { + kwsys::ofstream out(fileWithLongLine.c_str(), std::ios::binary); + if (!out) { + std::cerr << "Problem opening for write: " << fileWithLongLine + << std::endl; + return false; + } + out << firstLine << "\r\n\n" << secondLine << "\n"; + } + + kwsys::ifstream file(fileWithLongLine.c_str(), std::ios::binary); + if (!file) { + std::cerr << "Problem opening: " << fileWithLongLine << std::endl; + return false; + } + + std::string line; + bool has_newline = false; + bool result; + + // Read first line. + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || line != firstLine) { + std::cerr << "First line does not match, expected " << firstLine.size() + << " characters, got " << line.size() << std::endl; + return false; + } + if (!has_newline) { + std::cerr << "Expected new line to be read from first line" << std::endl; + return false; + } + + // Read empty line. + has_newline = false; + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || !line.empty()) { + std::cerr << "Expected successful read with an empty line, got " + << line.size() << " characters" << std::endl; + return false; + } + if (!has_newline) { + std::cerr << "Expected new line to be read for an empty line" << std::endl; + return false; + } + + // Read second line. + has_newline = false; + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || line != secondLine) { + std::cerr << "Second line does not match, expected " << secondLine.size() + << " characters, got " << line.size() << std::endl; + return false; + } + if (!has_newline) { + std::cerr << "Expected new line to be read from second line" << std::endl; + return false; + } + + return true; +} + +static bool writeFile(const char* fileName, const char* data) +{ + kwsys::ofstream out(fileName, std::ios::binary); + out << data; + if (!out) { + std::cerr << "Failed to write file: " << fileName << std::endl; + return false; + } + return true; +} + +static std::string readFile(const char* fileName) +{ + kwsys::ifstream in(fileName, std::ios::binary); + std::stringstream sstr; + sstr << in.rdbuf(); + std::string data = sstr.str(); + if (!in) { + std::cerr << "Failed to read file: " << fileName << std::endl; + return std::string(); + } + return data; +} + +struct +{ + const char* a; + const char* b; + bool differ; +} diff_test_cases[] = { { "one", "one", false }, + { "one", "two", true }, + { "", "", false }, + { "\n", "\r\n", false }, + { "one\n", "one\n", false }, + { "one\r\n", "one\n", false }, + { "one\n", "one", false }, + { "one\ntwo", "one\ntwo", false }, + { "one\ntwo", "one\r\ntwo", false } }; + +static bool CheckTextFilesDiffer() +{ + const int num_test_cases = + sizeof(diff_test_cases) / sizeof(diff_test_cases[0]); + for (int i = 0; i < num_test_cases; ++i) { + if (!writeFile("file_a", diff_test_cases[i].a) || + !writeFile("file_b", diff_test_cases[i].b)) { + return false; + } + if (kwsys::SystemTools::TextFilesDiffer("file_a", "file_b") != + diff_test_cases[i].differ) { + std::cerr << "Incorrect TextFilesDiffer result for test case " << i + 1 + << "." << std::endl; + return false; + } + } + + return true; +} + +static bool CheckCopyFileIfDifferent() +{ + bool ret = true; + const int num_test_cases = + sizeof(diff_test_cases) / sizeof(diff_test_cases[0]); + for (int i = 0; i < num_test_cases; ++i) { + if (!writeFile("file_a", diff_test_cases[i].a) || + !writeFile("file_b", diff_test_cases[i].b)) { + return false; + } + const char* cptarget = + i < 4 ? TEST_SYSTEMTOOLS_BINARY_DIR "/file_b" : "file_b"; + if (!kwsys::SystemTools::CopyFileIfDifferent("file_a", cptarget)) { + std::cerr << "CopyFileIfDifferent() returned false for test case " + << i + 1 << "." << std::endl; + ret = false; + continue; + } + std::string bdata = readFile("file_b"); + if (diff_test_cases[i].a != bdata) { + std::cerr << "Incorrect CopyFileIfDifferent file contents in test case " + << i + 1 << "." << std::endl; + ret = false; + continue; + } + } + + if (!kwsys::SystemTools::MakeDirectory("dir_a") || + !kwsys::SystemTools::MakeDirectory("dir_b")) { + return false; + } + + if (!kwsys::SystemTools::CopyFileIfDifferent("dir_a/", "dir_b")) { + ret = false; + } + + return ret; +} + +static bool CheckURLParsing() +{ + bool ret = true; + std::string url = "http://user:pw@hostname:42/full/url.com"; + + std::string protocol, username, password, hostname, dataport, database; + kwsys::SystemTools::ParseURL(url, protocol, username, password, hostname, + dataport, database); + if (protocol != "http" || username != "user" || password != "pw" || + hostname != "hostname" || dataport != "42" || + database != "full/url.com") { + std::cerr << "Incorrect URL parsing" << std::endl; + ret = false; + } + + std::string uri = + "file://hostname/path/to/" + "a%20file%20with%20str%C3%A0ng%C3%A8%20ch%40r%20and%20s%C2%B5aces"; + kwsys::SystemTools::ParseURL(uri, protocol, username, password, hostname, + dataport, database, true); + if (protocol != "file" || hostname != "hostname" || + database != "path/to/a file with stràngè ch@r and sµaces") { + std::cerr << "Incorrect URL parsing or decoding" << std::endl; + ret = false; + } + return ret; +} + +static bool CheckSplitString() +{ + bool ret = true; + + auto check_split = [](std::string const& input, + std::initializer_list expected) -> bool { + auto const components = kwsys::SystemTools::SplitString(input, '/'); + if (components.size() != expected.size()) { + std::cerr << "Incorrect split count for " << input << ": " + << components.size() << std::endl; + return false; + } + size_t i = 0; + for (auto& part : expected) { + if (components[i] != part) { + std::cerr << "Incorrect split component " << i << " for " << input + << ": " << components[i] << std::endl; + return false; + } + ++i; + } + return true; + }; + + // No separators + ret &= check_split("nosep", { "nosep" }); + // Simple + ret &= check_split("first/second", { "first", "second" }); + // Separator at beginning + ret &= check_split("/starts/sep", { "", "starts", "sep" }); + // Separator at end + ret &= check_split("ends/sep/", { "ends", "sep", "" }); + + return ret; +} + +int testSystemTools(int, char* []) +{ + bool res = true; + + int cc; + for (cc = 0; toUnixPaths[cc][0]; cc++) { + res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]); + } + + // Special check for ~ + std::string output; + if (kwsys::SystemTools::GetEnv("HOME", output)) { + output += "/foo bar/lala"; + res &= CheckConvertToUnixSlashes("~/foo bar/lala", output); + } + + for (cc = 0; checkEscapeChars[cc][0]; cc++) { + res &= CheckEscapeChars(checkEscapeChars[cc][0], checkEscapeChars[cc][1], + *checkEscapeChars[cc][2], checkEscapeChars[cc][3]); + } + + res &= CheckFileOperations(); + + res &= CheckStringOperations(); + + res &= CheckEnvironmentOperations(); + + res &= CheckRelativePaths(); + + res &= CheckCollapsePath(); + + res &= CheckGetPath(); + + res &= CheckFind(); + + res &= CheckIsSubDirectory(); + + res &= CheckGetLineFromStream(); + + res &= CheckGetLineFromStreamLongLine(); + + res &= CheckGetFilenameName(); + + res &= CheckTextFilesDiffer(); + + res &= CheckCopyFileIfDifferent(); + + res &= CheckURLParsing(); + + res &= CheckSplitString(); + + return res ? 0 : 1; +} diff --git a/testSystemTools.h.in b/testSystemTools.h.in new file mode 100644 index 0000000000..e4b89a7c19 --- /dev/null +++ b/testSystemTools.h.in @@ -0,0 +1,12 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_testSystemtools_h +#define @KWSYS_NAMESPACE@_testSystemtools_h + +#define RUNTIME_OUTPUT_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@" + +#define TEST_SYSTEMTOOLS_SOURCE_DIR "@TEST_SYSTEMTOOLS_SOURCE_DIR@" +#define TEST_SYSTEMTOOLS_BINARY_DIR "@TEST_SYSTEMTOOLS_BINARY_DIR@" +#cmakedefine KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS + +#endif diff --git a/testTerminal.c b/testTerminal.c new file mode 100644 index 0000000000..652830ccd9 --- /dev/null +++ b/testTerminal.c @@ -0,0 +1,22 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Terminal.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Terminal.h.in" +#endif + +int testTerminal(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + kwsysTerminal_cfprintf(kwsysTerminal_Color_ForegroundYellow | + kwsysTerminal_Color_BackgroundBlue | + kwsysTerminal_Color_AssumeTTY, + stdout, "Hello %s!", "World"); + fprintf(stdout, "\n"); + return 0; +} From 3068767747b6d6c13c28c020a3e2302dd58a1334 Mon Sep 17 00:00:00 2001 From: mingw-w64 Upstream Date: Sun, 25 Oct 2020 03:40:02 +0300 Subject: [PATCH 04/17] mingw-w64 2020-10-25 (12b5d134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code extracted from: https://github.com/mirror/mingw-w64.git at commit 12b5d1344c23c5fdba7fb2c771d0476c2220db16 (master). Upstream Shortlog ----------------- Alex Henrie (2): f424dc7d crt: Fix typo in rstrtmgr importlib. ecb4ff54 winnt.h: Add PROCESS_MITIGATION_POLICY values 11-14 and their structs. Alexey Pavlov (9): 88d15fb2 msidl.idl: Add missing declarations. 9fe24a15 include: Add evr.idl file. 08189cc9 include: Add mfplay.idl file. 93c7d161 Add missing features to shlwapi header ccaec143 Add interfaces frm evr header to libamstrmid c5d8619e Fix building runtime for Cygwin b0a5e6a2 Remove time functions export for 32 bit kernel32 as they export by winmm and already removed from 64-bit kernel32 ac5592b4 include: Add missing enum defines for IO_REPARSE_TAG_* 99b840e5 include/winsock2.h: Add missing IPPROTO_* defines Andrew Eikum (1): 6bd71e1d crt: Create pathcch link library Antoine Cœur (1): 954b97bc spelling Biswa96 (1): b7012ccb include/wincon.h: Add new PeusoConsole APIs for Windows 10 RS5 Biswapriyo Nath (145): 4539f448 include/winioctl.h: Add new device types. 04db0436 include/winbase.h: Add new PROC_THREAD_ATTRIBUTE values 5a88def8 include/evntrace.h: Add new datatypes and definitions b95e68ae crt/lib-common: Add more kernel32 exported functions 2c69c75d crt/lib-common: Add more advapi32 exported functions 12b82d07 Update tdh library 24842d45 Update Kernel32 and KernelBase export definition ce5078c9 Update ntdll export definition 5df7d5cf include/npapi.h: Update npapi header file b34afd3e include/npapi.h: Update npapi header file 30461094 include/npapi.h: Reformat some declarations. a04227bc include/wslapi.h: Add wslapi header file bfd2db7a crt/wslapi: Add wslapi library f657fb2a crt: Add api-ms-win-core-console-l1-1-0 library 410cbcef crt: Add api-ms-win-core-datetime-l1-1-0 library da215fcf include/sal: Update sal definitions 424d2edc crt: Add api-ms-win-core-comm-l1-1-0 047f9341 crt: Update rpcrt4 library 82e1234f crt: Update dnsapi library ee4ea73c crt: Update winhttp library c26aade1 crt: Update ntdll library 155bbd5d include/sdkddkver: Replace tab with one space 31801e20 include/sdkddkver: Add new define values 6abd3a55 include/securitybaseapi: Add CveEventWrite and DeriveCapabilitySidsFromName de8c771c crt/wininet: Remove ordinal values f72ffe61 crt/wininet: Update library 6e5f2557 crt/iphlpapi: Update library a6f0bf18 include: Add hvsocket file 1180ab95 include: update minwinbase header file 561388cb crt/urlmon: move to lib-common 5c107de2 crt/urlmon: remove ordinal values d9bfbd3a crt/urlmon: add more functions 2d52c4b3 include: update winreg header file b8c1a8ca include/winternl: update header file 7d56eb10 include/libloaderapi: update header file 693c269f include/dwmapi: update header file 575f218a include/uxtheme: update header file b4efa8a9 include/winsock2.h: add some flags 8a1f42c9 include/shtypes.idl: add more flags 103ead24 crt/shcore: move shcore to lib-common 4b52ae0a include/netfw: add INetFwRule2 and INetFwRule3 interfaces 5eece15a include/wincrypt: update header file a4de8df4 crt/gdi32: update import library ab54b0ed crt/lib64: add WinHvEmulation and WinHvPlatform library 3ac71ed3 include: add Hyper-V header files 395dcfde rename hyper-v headers and def files to lower case 7cfd6ff6 crt/websocket: move websocket to lib-common 9585e4f2 crt/d3d10: move d3d10 to lib-common 0e8f3b94 crt/d3d12: add d3d12 export library 9da214d9 crt/d3d11: update d3d11 library 784f34b8 crt: update micore.mri c26610ba crt: move mfreadwrite to lib-common 22333acf dxgidebug.idl: Import from wine. 06bc9552 thumbcache.idl: import from wine 3a99d7c6 dxva2api.idl: import from wine 04345388 crt: move ks to lib-common bbf165c7 crt: add ksecdd def files 23c8d91f crt: add netio def files 90d097a1 crt: update and move ndis to lib-common c8e562e9 headers: Import dxva.h from Wine. 297b3799 crt: propsys add def files 0fe2230a headers: sensors add missing guids bb0d63a2 headers: memoryapi add Windows 10 functions da69d7eb headers: winnt add structures for memory APIs fc3b60f4 headers: codecapi add missing enums 067214fc headers: add missing enum values and interfaces in mfobjects.idl 3c737ed6 headers: Import exdisp.idl and spatialaudioclient.idl from Wine. 8531603b headers: add vsserror.h a43a921d headers: add vss.idl f6bb0f7b headers: winerror.h add security error values df36f5de headers: update schannel.h ecb0de6f headers/mftransform.idl: replace cpp_quote with actual symbols 1c3e32a7 headers: move symbols from d2d1 to dcommon for wincodec e7f3f748 headers: import wincodec.idl from wine d19f72fd headers/wincon.h: add missing functions ab2fe27d headers: add dinputd.idl cad36811 headers/winerror.h: add directx error values 3412cd4f headers/inputscope.idl: add winapifamily conditions and ITfInputScope2 interface 47fb51f8 headers/dcomptypes.h: add winver conditions and missing enum c051a9a2 headers/Makefile.am: add missing idl file names b1fb31f0 headers: import dvdif.dil from wine 9468ebce headers: import wincodecsdk.idl from wine 0d73fc53 headers/ddk: add wdmsec.h file 9c8125af headers/devguid.h: add missing guids and winapi family 75967f8d headers: add netcfgx.idl 625ddf50 headers: add netcfgn.idl a61fa546 headers: add nserror.h cc95d4e2 crt/libsrc: include devguid.h in devguid.c and remove all defines 17a356e9 crt/libsrc: add missing headers in wbemuuid.c c24710ad crt/libsrc: add netcfg-uuid.c for network config interfaces 6b541a79 headers/wingdi.h: add missing symbols 223cf230 ddk/ntifs.h: fix compilation with struct STORAGE_QUERY_DEPENDENT_VOLUME_RESPONSE 3310d459 headers/ntdef.h: add missing symbols from reactos 87a4404c libraries/winpthreads: remove unused dwFlags variable in sched.c 1499b9bc crt: update api-ms-win-core-winrt-error-l1-1-1 b546ea63 crt: add api-ms-win-core-winrt-error-l1-1-0 to runtimeobject library fbf9730c crt: add missing apiset exports to runtimeobject library 76e56e6f crt/string: add parentheses to HASZERO macro to suppress gcc warning e7cbdb99 headers/apisetcconv.h: add WINSTORAGEAPI 23275a7d crt: add bluetoothapis export library 40ada3c5 headers: update windows hyperv files 03f7fcfb headers/knownfolders.h: add missing folder ids 9d8d52b1 ddk/scsi: add missing enum and define entries 944854bc headers/debugapi: add WaitForDebugEventEx for Win10 only aca21f93 crt: move dismapi to lib-common 7b4b28c1 crt: move wimgapi to lib-common 675fd4dd include/sdkddkver.h: add new NTDDI version defines 4ea074af include/cfg.h: add missing defines fe758f07 include/cfgmgr32.h: add missing defines 4b31ce8e include/psapi.h: update union PSAPI_WORKING_SET_EX_BLOCK 4e51dfbf include/security.h: add CLOUDAP_NAME define 5c137a75 headers: import files from wine 05df4cc2 headers/winuser.h: add missing symbols and defines 0f6395bd headers/windef.h: add missing symbols and defines d9a9ccd8 headers: import d3d12shader.idl from wine 4959a1ac headers/winres.h: add file, just includes winresrc.h a25dc933 headers/winver.h: add missing Ex APIs and defines 716676b8 headers: Import dwrite IDLs from Wine. 6abf1182 headers: Import d3d12.idl from Wine. 93a47c29 crt: add prntvpt export library 6ccd6ce0 include: add prntvpt.h 86a22fd1 crt: add htmlhelp export library be0b59ca headers/ddraw.h: Replace BOOL with WINBOOL type. aac28d62 headers/ddraw.h: Add MSABI_LONG macro for long values. 1fa82b3f crt/libsrc: include string.h for memcmp prototype 63c28e82 headers/sec_api: add fscanf_s 23e828bd headers/sec_api: add scanf_s 856054f0 headers/sec_api: add wscanf_s 7dc67104 headers/sec_api: add fwscanf_s f0ccc499 headers/sec_api: copy fwscanf_s to wchar_s.h file 98dad1fe headers/sec_api: copy wscanf_s to wchar_s.h file f14b748b include/winres.h: Add IDC_STATIC redefinition. e2d29885 crt: Update dxgi export library. ea52e5e8 headers: Import d3d12sdklayers from wine. 3f3ecfd2 headers: Add missing values of MAPPING_ENUM_OPTIONS structure members. 1c195839 headers: Add elssrvc.h header file. f8727367 crt: Update bcrypt export library. 9a963d23 headers: Update bcrypt.h header file. feff7165 crt: Update ncrypt export library. 1f8f672c headers: Add new functions in ncrypt.h. b8780db1 headers: Add IWMColorConvProps interface in wmcodecdsp.idl. 6bdcb3ad crt/lib32: Add argument bytes in api-ms-win-core-path-l1-1-0. e249108a crt/lib32: Add bytes of arguments in api-ms-win- files. f5ae5685 crt: Update powrprof export library. 172511d7 winpthreads: Add pthread_attr_getstack and pthread_attr_setstack. Chris Charabaruk (1): 1bb9dfc9 include/winnetwk: Fix oversighted BOOL in function proto Christian Franke (9): b4a4588b crt: Add support for `_FORTIFY_SOURCE`. 39654e37 headers: _FORTIFY_SOURCE: Print warning if original gets() is called. 802f866c header: _FORTIFY_SOURCE: Add _read() and read(). db643423 _FORTIFY_SOURCE: Fix usage of __gnu_inline__. 505de9b6 headers: _FORTIFY_SOURCE: Use __builtin_va_arg_pack() only if needed. 1e6e3429 headers: _FORTIFY_SOURCE: Allow to disable usage of __builtin_va_arg_pack(). 0983b5e7 headers: _FORTIFY_SOURCE: Add _[w][s]open() and [s]open(). a1b15755 headers: _FORTIFY_SOURCE: Allow to limit level for individual functions. 775df066 headers: _FORTIFY_SOURCE: Limit level for functions which work on raw memory. Corinna Vinschen (1): 77996bf8 winnt.h: Add SidTypeLogonSession declaration. Eric Hassold (1): d965518d include/mfidl.idl: Fix `MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE` Hugo Beauzée-Luyssen (22): 89350d72 crt: Add missing snprintf aliases to msvcr120_app.def.in dd221cf2 winbase.h: WaitForMultipleObjects is available on UWP d43dfe48 sysinfoapi.h: Allow some functions for UWP 3738707f winreg.h: Add missing WINAPI_PARTITION_DESKTOP guard d0607afb winstorecompat: Fix EnumProcessModule 710b8e00 winstorecompat: Don't build RtlAddFunctionTable on IA-32 d67540ce winstorecompat: Add RtlRestoreContext stub f7b2feb3 winstorecompat: Regenerate Makefile.in a3b01285 headers: ncrypt is available for UWP c515ce0c crt: Update processthreads libraries & header 7dacb2a5 crt: Update processenvironment libraries and headers ec07cf0f crt: Add namedpipe APIs d31f47bd crt: Add missing api-ms-win-core-file-l2-1-0 983b6f73 include/winbase.h: Remove tabs d5269ed5 Add missing IO function 9b1a191e Add missing api-ms-win-core-file-l1-2-2 e4afbd66 Move some functions declaration to fileapi.h 900fb281 fileapi: Use the correct macro for desktop + app 60d5baaa fileapi: Fix availability checks d80b3655 lib-common: Add missing functions to api-ms-core-file-l1-2-1 e8c433c8 crt: api-ms-win-core-file-l2-1-0: Fix typo fa3df3b6 crt: Add api-ms-win-core-psapi-ansi-l1-1-0 Jacek Caban (121): ee9fc3d0 d2d1.h: Work around GCC not being compatible with MSVC in aggregate retuns handling. 71f65bef Updated imported headers to current Wine version. fdcc1e82 Moved wscapi.def to lib-common and use it for x86_64. d5464b3a dcomp.h: Reorder interfaces so that IDCompositionVisual is declared before it's used. a0ddaa98 stdio.h: Added support for _vscwprintf in ucrt-based builds. 14a8c299 stdio.h: Use reserved identifier for temporary variable. 52a34d52 ucrtbase: Provide non-inline version of _vsnwprintf. 16151c44 ucrtbase: Regenerate makefile. 49ca7cfe stddef.h: Avoid max_align_t declaration conflict with clang stddef.h. 91b7cdad sdkddkver.h: Add missing NTDDI_WIN10_* defines. a143277e wintrust.h: Added missing win8+ hCatAdmin field to WINTRUST_CATALOG_INFO. 10204318 dhcpcsvc.def: Use lib-common for importlib. cbfe5f50 Updated imported headers to current Wine version. b9a6ba0c libmincore.a: Add new importlib. 5b72d83e winternl.h: Fix _PEB declaration. 079ed545 winbase.h: Add missing PROCESS_CREATION_* defines. cb6bc23b Update widl to current Wine version. 77c2db61 _mingw_stat64.h: Define _fstat, _stat and _wstat to *32 variants when appropriate. cb090aff dhcpcsvc.def: Add missing entries. cfd85ebe winnt.h: Fix FILE_ID_128 declaration. 03ca1a60 runtimeobject.mri: Use common .mri file for all architectures. a7f2b2b9 synchronization.mri: Use common .mri file for all architectures. 76d409af vfw32.mri: Use common .mri file for all architectures. 21b6366d windowsapp.mri: Use common .mri file for all architectures. a91a7e40 _mingw_mac.h: Enable WIDL_EXPLICIT_AGGREGATE_RETURNS workaround for ABI incompatibility on affected platforms e3542077 widl: Updated to current Wine version. ed8173d5 Updated imported headers to current Wine version. b32ed6fb winternl.h: Added PUBLIC_OBJECT_TYPE_INFORMATION declaration. 70860d94 inttypes.h: Take into account __USE_MINGW_ANSI_STDIO and msvcrt version instead of depending on _mingw_print_p*.h headers. 8a9a6eeb widl: Updated to current Wine version. 0d46d8c3 widl: Imported to current Wine version. 06487da9 Regenerate headers using async_uuid with recent widl. 154a4e49 Regenerate direct-x headers using recent widl. 97452087 Regenerate more header files with recent widl. 6bddb1b6 Partially revert 97452087928e38c9bcf. 3577667d rpcndr.h: Fix MIDL_user_allocate declaration. 172cf552 widl: Updated to current Wine version. 99d13399 ntdllcrt: Use separated import library for ntdll.dll C runtime exports. 2d4e517a Updated imported headers to current Wine version. ec4dc422 Update imported headers to Wine 4.2. 0e1da6b5 Update widl to Wine 4.2. 2d83f7b6 string_s.h: Add some missing C++ overloads. 3bef7c22 Remove support for --disable-secure-api. 1461c4ac corecrt.h: Add new file and move declaration from crtdefs.h there. 228a789d corecrt_wstdlib.h: Add new file and move some relevant declaration to it. b6ecdbe5 widl: Updated to current Wine version. 62b07d20 headers: Updated imported headers to current Wine version. 425c3fec windows.system.idl: Add new file. d1980f9a dispatherqueue.h: Add new file. 6c8dfd07 libd3dcompiler.a: Default to d3dcompiler_47.dll to match headers. f2e459ba intsafe.h: Add SizeTToUInt32. ba519cc4 configure: Regenerate with autoconf 1.16.1. 713a108e crt: Use importlib for _assert. e3618a17 crt: Use importlib for _wassert. cfcc63fa msvcrt.def.in: Fix _CxxThrowException import on x86. f870123b crt: Split mingw_getsp and longjmp into separated files. 844cb490 crt: Use importlibs for longjmp. 13224d1d crt: Get rid of spawnv* forwards in mingwex. c72c3887 crt: Use importlibs for execv* functions. 19b6d96e crt: Use importlibs for _difftime* functions. c128c4b4 time.h: Use _CRTIMP on more time functions cbaa9a3d time.h: Unify inline attribute strategies for time functions c1e9f6cf crt: Move __mingw_setusermatherr and __mingw_raise_matherr into a separated object file. b13e8de2 mfobjects.idl: Add missing MFVideoTransferMatrix entries. 6988d73a time.h: Use static inlines for time 32/64-bit forwarding functions. d539d36f widl: Update to current Wine version. 28a1ea21 winstorecompat: Remove no longer needed _wassert. 69effce7 pthread_unistd.h: Don't define _POSIX_THREAD_SAFE_FUNCTIONS. e8db6cea time.h: Use __forceinline for *_r functions. 5c7126bc crt: Remove no longer used _encode_pointer and _decode_pointer. 8b2ece59 headers: Use _UCRT to signal whether the UCRT is used 75d9c5a7 librpcrt4.a: Drop @0 suffix from varargs functions. 04e6f363 Updated imported headers to current Wine version. c24c3920 netlistmgr.idl: Import from Wine. f3462200 widl: Updated to Wine 4.12.1. b7e28c0b headers: Updated imported headers to Wine 4.12.1. 782c94fb headers: Regenerate more headers with recent widl. 30afa461 unknwn.h: Revert to old widl. 60d5a66a widl: Updated to current Wine version. 708498d6 headers: Regenerated imported headers with current widl version. bae5878f widl: Updated to Wine 4.19. 85b86362 headers: Updated imported headers to Wine 4.19. 95004ac1 wincrypt.h: Add missing CERT_CHAIN_* flags. 1b373bee inputscope.idl: Add missing InputScope values. 02aa03a7 mshtml.idl: Correctly import dxgitype.idl. 46d18cc9 widl: Update to Wine 5.0-rc1. 49e9a673 include: Update imported headers to Wine 5.0-rc1. d0de7534 include: Move headers from direct-x/include/ to include/. f701c4c8 headers: Update imported headers to Wine 5.0-rc4. 3efdceed headers: Get rid of check for DX headers presence. f183d3b8 headers: Get rid of _mingw_directx.h. 3f92232d headers: Remove remaining direct-x directory usage. 00331a83 configure: Deprecate directx SDK option. 53fab17a headers: Updated imported headers to current Wine version. 7eff69b8 crt: Regenerate makefiles. 0207b49f headers: Update imported headers to current Wine version. 7542dd94 headers: Update imported headers to current Wine version. e7e8cae7 headers: Add corecrt_stdio_config.h header. 41bcbb89 headers: Update imported headers to current Wine version. f3893894 headers: Update imported headers to current Wine version. b21c5ed9 headers: Actually import spatialaudioclient.idl. fd5d6c8f crt: Don't use __mingw_init_ehandler on toolchains using SEH. 3b796166 headers: Use wine-import.sh for dsconf.h. 287c6c0b headers: Update imported headers to current Wine version. 84c9343c widl: Compute relative binary to include dir path in configure. dc2a522f widl: Remove no longer needed helpers. 7441d866 widl: Updated to Wine version 3bb824f98891e8. 99ca150e headers: Updated imported headers to current Wine version. b2461592 crt: Use corecrt_stdio_config.h instead of local UCRTBASE_* defines. a523bb27 headers: Use corecrt_stdio_config.h instead of local UCRTBASE_* defines. f6b0a35d winnt.h: Add missing STATUS_HEAP_CORRUPTION define. 6936d7df widl: Update to current Wine version. 6c8c2a07 headers: Updated to current Wine version. 3419b2d4 headers: Updated to current Wine version. 81c64730 headers: Update imported headers to current Wine version. afda4ac8 widl: Updated to current Wine version. b2e5d332 headers: Update mscat.h to current Wine version. 50bcd814 headers: Import d3d11on12.idl from Wine. 41b0e14e widl: Update to current Wine version. a33346ef headers: Updated to current Wine version. bd8ca6c3 headers: Update imported headers to current Wine version. James Ross-Gowan (1): 1067c998 include/shellscalingapi.h: Add new header file Jehan (2): fb232993 headers: non C90-compliant C++ style comments break builds. 823bc20b headers: define various *_EPSILON in float.h. Jehan Pagès (2): bb40fb26 headers: make Mingw-w64 pass -Wstrict-prototypes. 6f44da5e headers: make Mingw-w64 pass -Wstrict-prototypes. Johannes Pfau (2): 6a5c1535 Add _ftime aliases for all msvcr versions. fde585a1 Also provide _utime32 inline definition for 32 bit systems Jonathan Yong (6): 843c9d11 crt: Regenerate x86/x86_64 libcrypt32 and libdpapi cb019894 mingw-w64-crt/configure.ac: Remove reference to experimental.txt 69c8fad6 mingw-w64-headers: Bump __MINGW64_VERSION_MAJOR for new release c24915bd configure: regenerate 905f11f8 _mingw_mac.h: bump to 8.x 2732d54d mingw-w64-headers: bump _mingw_mac.h to 9.0.0 Kleis Auke Wolthuizen (1): 0fb81dec crt: Fix CPPFLAGS for arm32/arm64 dinput/dinput8 Liu Hao (96): 696b37c3 crt/misc/imaxdiv.c: Fix prototype of `lldiv()`. 73fd952e headers/include/dwrite.h: Fix definition of DWRITE_HIT_TEST_METRICS. 1c46c9f7 Revert "crt: Unify and simplify handling of constructor/destructor lists" 1b29d1bc include/wincon.h: Add new console mode flags. 2de891f8 ddk/wdm.h: Remove the inline definition of `InterlockedAdd64()`. d72c4fe6 crt: Regenerate configure. bed29d9f include/ws2tcpip.h: Do not declare non-existent `FreeAddrInfoExA()`. 6680efaf crt/time.h: Always provide overridden time functions, even for MSVCRT. 50a771fd crt/time.h: Adjust a blank line. 5e7a3a99 crt/msvcrt.def.in: Always declare `_mkgmtime{32,64}`. d5274305 crt/misc/fesetenv.c: Do not clobber `env` with `FNSTENV` 4ed230ca crt: Regenerate configure. ccca5685 Revert "include/npapi.h: Update npapi header file" a47ec623 crt: Regenerate configure 65042f86 crt/kernel32.def.in: Remove multimedia timer functions again. e42c609a crt/lib-common/msvcrt.def.in: Export `_futime32()` on x86 and x64. 15986901 include/ntsecapi.h: Add missing `__stdcall` specifiers. 0dfb3d3f crt/msvcrt.def.in: Export `_utime32()` and `_wutime32()` on x86 and x64. d1983de2 crt: Regenerate Makefile. d5bf9a58 crt: Regenerate Makefile. 0a57d9f2 include/ws2tcpip.h: Fix prototypes of `InetNtop{A,W}`. 16499046 crt/libkernel32.def: Comment out `OpenProcessToken@12` for XP compatibility. 98ee5b09 crt/lib32/kernel32.def: Comment registry functions from ADVAPI32.DLL out. 2a439e13 winpthreads/cond.c: Only update `waiters_count_` with `waiters_count_lock_` locked. b2302cd6 winpthreads/cond.c: Remove waits for `sema_b` from wait functions. 7f2392c2 include: Regenerate configure. f186f68d include/GL: Update to a more recent Git version. d793e0ef include/KHR: Update to more recent Git version. 3e6c10ae crt: Regenerate configure. d8f91451 crt: Regenerate configure. ab9162c3 include/ddk/ntintsafe.h: Remove `WINAPI_PARTITION_SYSTEM`. 8331eb05 crt/math: Implement standard-conforming `frexp()`. 64aeb19c crt: Regenerate configure. b1e40dba crt: Regenerate configure. 1ebdd63c Revert "winpthreads/cond.c: Remove waits for `sema_b` from wait functions." 6b82d31b include/libloaderapi{,2}.h: Don't mistake `BOOL` for `WINBOOL`. 4fc998e6 include/{cfgmgr32,devpkey}.h: Add a missing `#include ` 140cdf09 include/shtypes.h: Regenerate from IDL 3cc3af23 include/shtypes.h: Regenerate from IDL 47ce9fd8 crt/Makefile.in: Regenerate 6aa39bf2 stdio/mingw_wvfscanf.c: Fix segmentation fault when a char or string format (without malloc option) is used. e46aa77c stdio/mingw_wvfscanf.c: Return `EOF` on failure rather than `WEOF`. 9e9c5ab7 include/netfw.h: Regenerate from IDL 5115f38f crt: Regenerate configure 5d869f9b crt/time.h: Move POSIX re-entrant functions into the `extern C` block. 9c158e1d crt: Regenerate configure 71a14c99 crt: Regenerate configure 6f1130d3 crt: Regenerate Makefile.in b9a5ab3f include/mfidl.h: Regenerate a39cd936 crt: Regenerate configure 9942b32c crt: Regenerate Makefile.in a06685dd crt/fmal.c: Use hardware to handle potential denormal numbers fd78dd54 crt/fma{,f}.c: Implement FMA for `double` and `float` properly c7fb1a6e crt: Add missing 'libwebsocket.a' dependency decf415f crt: Regenerate Makefile.in 6d50cee6 crt: Regenerate Makefile.in e57a6671 crt: Regenerate Makefile.in 4c467440 crt: Regenerate Makefile.in b5f517b2 include/wincrypt: Eliminate a line of C++ comment fdb88f69 genlib: Regenerate configure ae131c31 include/mfobjects: Regenerate .h from .idl a749dbad crt: Replace CR+LF with LF 10060c25 include/mfidl.h: Regenerate from IDL 26c43cab include/{mfidl,mfreadwrite}.h: Regenerate from IDL b35310ea crt: Regenerate Makefile.in 86ae33ec include/vss.h: Regenerate from IDL 53854979 headers: Regenerate configure 223de3ab headers/mftransform.h: Regenerate from IDL 5976e54a include/dinputd: Generate H from IDL 423b4232 headers: Regenerate configure 13862f2a include/inputscope: Regenerate from IDL ba936ce8 crt: Add missing functions in msvcr80.def a2feff99 include: Hide inline wrappers when building the CRT 0df1b769 headers: Regenerate Makefile.in 779a8f6a headers: Generate netcfgx.h from IDL 6be3dc50 headers: Generate netcfgn.h from IDL 51dc05bb headers: Regenerate Makefile.in 621d33d9 crt: Add `__ms_*` aliases for `*printf` and `*scanf` functions e46c5521 crt/stdio: Add declaration for `__ms_*` aliases 0d57b457 crt/stdio: Restore `__ms_vw*scanf` wrappers 61ce4119 crt/wchar: Copy wide stdio functions from e8d7c1b3 crt: Regenerate configure and Makefile.in e82b4f56 winpthreads: Always define `__USE_MINGW_ANSI_STDIO` to zero 1c302d25 winpthreads: Regenerate Makefile.in 11be2657 crt: Regenerate Makefile.in df6c08b9 crt/stdio/fseeko64: Remove the now superfluous `mingw_dosmaperr()` edeeef2a crt/stdio/fseeki64: Copy-n-paste from `f{tell,seek}o64()` 295fafcf winpthreads: Call `_fpreset()` for new threads cb59f19c crt: Regenerate Makefile.in 086fac13 include/winbase.h: Remove mistaken `#ifdef` around `THREAD_INFORMATION_CLASS` 6bc8db72 crt: Regenerate Makefile.in d54c2900 include/dxva2api.idl: Fix build error when compiled as C++ f90e5ef1 include/dxva2api: Regenerate from IDL fc2b4752 headers: Update imported headers to current Wine master eaea8766 include/wmcodecdsp: Regenerate header from IDL d92058a2 crt: Regenerate Makefile.in Marisa-Chan (1): d4822b48 Do not overwrite env value by loading current fpu state. Martin Mitáš (1): 60ce40de headers/winhttp: Add some missing macros into winhttp.h Martin Storsjo (3): b5b4075f widl: Set a correct system_result_size for the macOS case d0e46d2d Revert "widl: Use separated buffer for result in simplify_path." ae603a85 widl: Use memmove instead of memcpy for copies that potentially can overlap Martin Storsjö (272): ba5964cb headers: Add missing BitScanForward/Reverse functions for arm and arm64 a7aeaae1 headers: Use the same 64 bit compatibility wrappers for arm as for i386 b2ac05b5 headers: Add missing 64 bit InterlockedBitTestAndTest functions for arm64 95d6af06 crt: x86: Fix the exponent mask in copysignl for x86_64 1ace9ddd crt: Add a new separate library libucrt.a, linking to api-ms-win-crt-*.dll instead of ucrtbase.dll 5c9db71d crt: Regenerate Makefile.in ca0f283f winstorecompat: Regenerate Makefile.in cd320ea6 headers: Update the _TEB struct to include the ProcessEnvironmentBlock member c5715870 crt: Add a def file for vcruntime140_app.dll 18ca164a crt: Regenerate Makefile.in 787a53a0 crt: Share libwindowsapp.a, libruntimeobject.a and libsynchronization.a between lib64, libarm32 and libarm64 17e239b7 crt: Regenerate Makefile.in f3a6db27 crt: Avoid using _mbslen in misc/wcsto{f,ld}.c 868fe281 crt: Split wassert.c into a separate assert.c 25e24639 crt: Regenerate Makefile.in 0e1f4135 winstorecompat: Add an implementation of EnumProcessModules 38646ba4 winstorecompat: Regenerate Makefile.in 39a534aa winstorecompat: Add stubs for Rtl functions used by the mingw-w64 crt wrapping 51fa2e2b winstorecompat: Regenerate Makefile.in f3e0fbb4 crt: Add an implementation of __cxa_atexit and __cxa_thread_atexit b585c7b5 crt: Regenerate Makefile.in 815c16d5 crt: Declare _register_thread_local_exe_atexit_callback in headers, provide fallback b84ab0fc crt: Regenerate Makefile.in 0fc90153 crt: Expose a private variable that indicates whether the module is an exe or dll 691566fc crt: Use _register_thread_local_exe_atexit_callback for TLS dtors 82b169c5 headers: Check for the new clang float.h include guard 0204e469 crt: Unify and simplify handling of constructor/destructor lists 4df4b6bb crt: Build the SEH inline assembly with clang 7 0a78be1a headers: Correct the parameter type to PGET_RUNTIME_FUNCTION_CALLBACK for arm 76c6448a headers: Make the x86_64 UNWIND_HISTORY_TABLE struct match the windows sdk 32be4ee1 headers: Add missing alignment for CONTEXT for arm/aarch64 b0adf1e6 headers: Add the missing declaration of DISPATCHER_CONTEXT for arm 4c2e3822 headers: Add missing aarch64 declarations for unwinding related structs/functions 94a8086f crt: Add a missing include of stdlib.h, for calloc/free 55e067dc crt: Skip destructors registered with __cxa_atexit when exiting from _exit/ExitProcess 2c746c63 crt: Change comment char from * to ; in mincore.mri baaf945d crt: Check whether the linker provides __CTOR_LIST__, don't check for __clang__ f89e0e3e crt: Regenerate configure and config.h.in 30af1825 Revert "crt: Check whether the linker provides __CTOR_LIST__, don't check for __clang__" 39495289 crt: Comment out building libmincore.a for arm64 f0c7d01e ucrt: Improve handling of timezone and tzname 939eb7bf ucrt: Don't define daylight as a macro in the header ccda8b52 crt: Check whether the linker provides __CTOR_LIST__, don't check for __clang__ 08fe64f0 crt: Regenerate configure and config.h.in bda8fc00 crt: Avoid using AC_LINK_IFELSE at all for the linker test 22374844 crt: Regenerate configure 7f9d8753 headers: Update the data type of Name in IMAGE_IMPORT_BY_NAME c2449752 headers: Declare __C_specific_handler for x86_64, arm and aarch64 b6e63887 headers: Check whether intrinsics in winbase.h are available as builtins 7f5c10ea headers: Declare the VirtualProtectFromApp function e1c9831d crt: Remove VirtualAllocFromApp from kernel32.def 22be61df crt: Remove a leftover chunk from 21b6366dd9cc3b8a6fe11698b326aa2eb88acc7d 161a6439 crt: Regenerate Makefile.in 06cb0965 crt: Regenerate configure 8ad91360 widl: Stop using AC_FUNC_MALLOC, AC_FUNC_REALLOC and AC_FUNC_STRTOD 1c35bd29 widl: Regenerate automake/autoconf files. f1a55b8f widl: Allow overriding the default include path 5a61034d widl: Regenerate Makefile.in and configure 7e9a76e9 ucrt: Remove a leftover comment b1de317a ucrt: Move _snwprintf and fwprintf to separate translation units 9077bf73 crt: Regenerate Makefile.in c69c7a70 headers: Update the threadlocinfo struct for ucrt 79874445 headers: Fix the preprocessor conditions from c69c7a706 dc348cb1 crt: Correct the availability for __C_specific_handler 8b2c7826 headers: Avoid builtin clash with _xgetbv in Clang 9 0e178e50 crt: Share mswsock.def between libarm32 and lib64, use for libarm64 671dc841 crt: Share authz.def between libarm32 and lib64, use for libarm64 2ab57c3c crt: Uncomment building libmincore.a for arm64 8fcb463f crt: Regenerate Makefile.in. 9707a703 headers: Fix a typo in 3bef7c2206bb6f9552ea7e61315c4bf7af3aa6c9 55cc16ea headers: Remove an unbalanced ifdef from 228a789d38072ceea3cad23be7354db3ec0a8703 6fd1987a headers: Add missing extern "C" from 228a789d38072ceea3cad23be7354db3ec0a8703 436ad4b8 headers: Only pass a frame pointer to setjmp if SEH is enabled 931eb280 crt: Regenerate Makefile.in after the last few commits. 59421922 crt: Add missing dependencies for libmincore.a and libwindowsapp.a 62366fde headers: Fix an accidentally inverted ifdef 16380b0b crt: arm: Deduplicate C based arm/arm64 math implementations 963fbdaa crt: Regenerate Makefile.in b46cf874 crt: arm: Add forwarding functions for scalbln similar to scalbn 294a5169 crt: arm: Use import libs for math functions eea1e86d crt: Regenerate Makefile.in e4fae63a crt: arm: Provide fmodl as an alias for fmod b3c477e6 crt: arm: Add implementations of remainder and remquo for msvcrt c439ab59 crt: Regenerate Makefile.in c9dbd5c1 crt: Skip x86-only symbols from libmsvcrt-os.a for arm ae7427be crt: Don't provide the getpid == _getpid alias for arm a85ac79a headers: Redirect _environ to the _get_environ function in msvcrt.dll for arm/arm64 e7267842 headers: Don't declare getpid for msvcrt versions where it's missing 40c1ea8c crt: Fix the getpid alias for libucrtbase.a for arm 0e349291 crt: Implement a fallback _getpid function for msvcrt.dll for arm/arm64 7a9ac3a7 crt: Regenerate Makefile.in c9965793 crt: Don't create getpid == _getpid aliases for msvcr120_app bb8ca8cb crt: Add getpid and _getpid fallbacks to the msvcr120_app import libraries 6482f9de crt: Regenerate Makefile.in a99578e9 winstorecompat: Remove the getpid fallback 1b7754a4 winstorecompat: Regenerate Makefile.in c7c58c56 crt: arm: Implement expm1 and log1p fallbacks for msvcrt.dll 6748e8e8 crt: Regenerate Makefile.in 544e5457 crt: arm: Implement acosh/asinh/atanh fallbacks for msvcrt.dll c3c05375 crt: Regenerate Makefile.in c61763cc crt: x86: Make acosh(infinity) return infinity as it should 983ccc9c crt: x86: Add the missing _copysignf function in libmsvcrt-os.a for i386 631c14cc crt: Regenerate Makefile.in 7c637cd7 crt: arm: Add an alias for powl to pow, on arm/aarch64 69af6ee1 crt: arm: Fix rounding for FE_TONEAREST in llrint* 1b5ae4b5 headers: Use proper types for InetNtopA/W fe3daacd crt: arm: Provide logb* and ilogb* for msvcrt.dll for arm/arm64 443e5456 crt: Regenerate Makefile.in be288533 math: Change FP_ILOGBNAN to match UCRT 4bfe743e crt: x86: Correctly handle denormals in the logb functions 4ef8254b math: Don't read a double aliased via a long double struct 6a9bed7b crt: Include math.h in signbitl.c instead of duplicating declarations e33afcd8 math: Don't do pointer type punning via a union 06c9d768 headers: Use _get_environ on all CRT versions except UCRT on ARM 5b066325 headers: Replace checks for __MSVCRT_VERSION__ against 0x1400 with _UCRT 8627c03d headers: Replace mentions of ucrtbase with the more general name ucrt edd674fb crt: Use _UCRT for specifying the CRT to use in certain files 94a28397 headers: Change __MSVCRT_VERSION__ to use proper hexadecimal values for CRTs >= 10 498bf00a headers: Regenerate configure 3cf1c689 crt: Add an implementation of gets() for msvcrt.dll for arm/arm64 f8e2c9ac crt: Regenerate Makefile.in 8b9ea8c4 crt: Call the right __stdio_common_* function in UCRT _vsnwprintf d95acea6 headers: Use the msvcrt/ucrt setjmp functions on ARM64 if SEH is available 494dcbbd crt: Provide an empty implementation of __set_app_type for msvcr120_app.dll b75c6140 crt: Regenerate Makefile.in 18249f31 crt: Merge msvcr120_app.def.in for 32 and 64 bit x86 269b3478 crt: Regenerate Makefile.in 07d8e63d crt: Call the right function for newmode from ucrtbase's __getmainargs ebf4bf9d crt: Make a compat ___mb_cur_max_func on i386, to avoid forcing a dependency on XP a4d30d3d crt: Regenerate Makefile.in b7df15ec math: Make lgammaf(-INFINITY) return positive INFINITY, like lgamma and lgammal 89ec0a8f math: Fix the return value for tgamma for zero and negative integers be8544ed math: Don't use the __INFL constant directly in hypotl e2301e0a math: arm: Make coshl/sinhl/tanhl call cosh/sinh/tanh 4375b931 math: arm: Add more aliases for -l suffixed math functions 7d929f71 math: arm: Make local -l suffixed functions call unsuffixed ones 2e7a02a5 math: Fix cosh(-INFINITY) to return +INFINITY 6765d537 math: Properly propagate input NANs in a few functions 41d1e495 math: arm: Don't link directly against msvcrt.dll's logb and pow functions f52b8e0f crt: Regenerate Makefile.in a84d22e0 ucrt: Don't use the UCRT lgamma functions on any architecture e5d1fe45 ucrt: Don't use the float env functions from the UCRTt library d8ed328d ucrt: Don't use long double functions from UCRT on x86 0dce6631 crt: Regenerate Makefile.in cd485c6c crt: Make the ucrt _vsnwprintf function use UCRTBASE_PRINTF_DEFAULT_WIDE 0a1d4954 headers: Default to the legacy wide string mode for ucrt 94efbac6 headers: Don't use __gnu_inline__ with __mingw_ovr in C++ mode d8183e4c ucrt: Avoid using the UCRT long double nanl function on x86 27af401f headers: Add new missing PF_* macros to winnt.h c2b93c56 crt: Silence warnings about unused variables 341e5bd3 crt: Add compatibility wrappers for _create_locale and _free_locale in msvcrt.dll 3e311db9 crt: Regenerate Makefile.in 2ce6f4b1 headers: Add _beginthread_proc_type and _beginthreadex_proc_type typedefs 211af1e7 ucrt: Use multibyte functions from ucrt instead of libmingwex c25d7dd8 crt: Regenerate Makefile.in 52d13f93 headers: Avoid c99 style comments in headers 157375b8 crt: Quote occurrances of TARGET_SYSTEM_ROOT, to fix installing into paths that contain spaces cf607056 crt: Regenerate Makefile.in e39d0f34 widl: Quote path names in the makefile, to fix installing into a path that contains spaces 1f903cc1 widl: Regenerate Makefile.in 2beac2e3 crt: Fix sscanf with double/long double output for arm 5bddbd2d crt: softmath: Split out the basic type and macro definitions out of softmath/bsd_private*.h to bsd_private_base.h b390807d crt: arm: Replace the assembly implementations of trunc* by a bit twiddling implementation 00f0339b crt: Regenerate Makefile.in d13613ac crt: arm: Use a bit twiddling implementation of rint* 68827dd5 crt: Regenerate Makefile.in 6c69c551 crt: arm: Make nearbyint* just call rint*, with backup/restore of float environment flags 6f4224da crt: arm: Use bit twiddling implementations of remquo* 00c44c02 crt: Regenerate Makefile.in c27765e2 crt: Split out the __cxa_atexit and __cxa_thread_atexit entry points to separate files b2525705 crt: Regenerate Makefile.in 743684f8 headers: Fix a use of WINAPI_FAMILY_PARTITION in fileapi.h 1930ffb6 headers: Remove a duplicate declaration of GetFileType f2489543 crt: Sync comments about libraries handled specially in Makefile.am 77ec1e27 crt: Regenerate Makefile.in 251659fd crt: Share dinput.def and dinput8.def with arm32 and arm64 10b1d916 crt: Regenerate Makefile.in 403165c2 crt: Share setupapi.def between x64 and arm32, provide for arm64 a90be296 crt: Regenerate Makefile.in fc3c8ad7 headers: Make conio.h self-sufficient in UCRT mode 3a112767 crt: Make __ms_snprintf and __ms_vsnprintf aliases for snprintf and vsnprintf f302654b crt: Regenerate Makefile.in 699903dc crt: Regenerate Makefile.in d5fa66cc widl: Remove an unnecessary platform specific ifdef 5be3afb3 crt: Regenerate Makefile.in 6c3fd730 crt: Build libks.a, libksecdd.a and libnetio.a for arm32 as well 2fc2a668 crt: Regenerate Makefile.in ae95d7ca crt: Move stdio/[v]snprintf.c to libmsvcr*.a from libmingwex.a 62259d49 crt: Regenerate Makefile.in 5af8d911 crt: Remove __chkstk from libkernel32.a for arm32 153c2808 crt: Make evr.def shared, make it available for arm64 b5706f8b crt: Regenerate Makefile.in d8275c19 crt: Provide _vscprintf as a non-inline function for UCRT c4617bac crt: Regenerate Makefile.in e70e84a7 headers: Fix the return value for swprintf and vswprintf for UCRT d42a2cfa headers: Avoid "int ret" in headers 2c4f4279 headers: Avoid "__builtin_va_list ap" in headers 6bff0fac headers: Avoid a few more cases of unreserved identifiers in parameter names 78276d42 crt: Regenerate Makefile.in 0db16e38 crt: Merge cfgmgr32.def and provide it for arm64 7c03b11b crt: Regenerate Makefile.in b46a25b4 crt: Move the msvcrt snprintf/vsnprintf aliases into separate object files 629fd2b1 crt: Regenerate Makefile.in 5511aa9b Revert "Avoid declaring something extern AND initializing it." 84b18015 headers: Use a custom macro for declaring extern const variables 41470f3d crt: Remove a leftover declaration of __MINGW_IMP_SYMBOL(_fmode) 903e1acb crt: Fix the initialization of the _commode variable 870c8685 crt: Use __p__commode instead of __MINGW_IMP_SYMBOL(_commode) for initialization e70faa65 crt: Regenerate Makefile.in 0d543332 crt: Remove unused/unnecessary declarations of _commode in internal.h 7e20be76 headers: Use EXTERN_GUID and DEFINE_PROPERTYKEY instead of a custom macro in mftransform.idl a307fdb0 headers: Fix missing enum values in mfobjects.h 468d3c9b headers: Include codecapi.h in uuids.h and define UUID_GEN if INITGUID is defined c1d15f07 headers: Add a few more guids and enums to codecapi.h 0645e6ff headers: Add a few more new guids to mftransform.idl 649c0324 crt: Use -mfpu=vfpv3 instead of -mfpu=vfp for arm32 780dacfa crt: Regenerate Makefile.in e72918f8 crt: Replace the arm version of exp2.c with assembly files f384596f crt: Regenerate Makefile.in 3f40dd32 crt: Convert the arm sincos.c to assembly e3665a85 crt: Regenerate Makefile.in 2434ba2b headers: Don't have a define expand to something containing defined() c286a0ba Revert "headers: move the C++ check for interlocked API" 68906703 crt: Share powrprof.def between lib64 and libarm32, use it for libarm64 e52226f3 crt: Regenerate Makefile.in e6ac7e42 crt: Remove the vestigial gs_support.c 329034c0 crt: Regenerate Makefile.in eb46f443 headers: Sync changes from stdlib.h to wchar.h from a2feff99e4f bedff472 headers: Don't use the 'inline' attribute on Clang when targeting C89 ed041dba headers: Fix include order of fvec.h/ivec.h/dvec.h referring to each other bc1ff01f winstorecompat: Regenerate Makefile.in 1724dbb6 crt: Build crt sources with -D__USE_MINGW_ANSI_STDIO=0 cdc83d46 crt: Regenerate Makefile.in 814f5270 winstorecompat: Use __asm__() instead of asm() for setting symbol names 64619464 winstorecompat: Add a cast to silence a warning about conversion between void pointer and function pointer b0d8fcd1 winstorecompat: Fix the return type of the non-i386 version of __imp__beginthreadex 4c8a7f3e winstorecompat: Add missing WINAPI in the GetUserName function pointer declaration 1c661aea crt: Remove the unused mingw-fseek.c f43d6cb5 crt: Regenerate Makefile.in d6c933ed crt: Don't make sections executable when not necessary 43f2d5ca winstorecompat: Regenerate Makefile.in 04eb1d4f winstorecompat: Avoid warnings about redefining _WIN32_WINNT in the Win10 library 7df01ff1 winstorecompat: Regenerate Makefile.in 02f67c97 crt: Regenerate Makefile.in bd0b4630 crt: Regenerate Makefile.in 88ed8940 crt: Fix a typo in the dependencies in 17eff275e71bf1f716c6a3085818e4843ee84107 c1ed48c2 Revert "crt: Move stdio/[v]snprintf.c to libmsvcr*.a from libmingwex.a" 60832967 crt: Regenerate Makefile.in bb73d2e3 winstorecompat: Regenerate Makefile.in 96483fc8 headers: Update libloaderapi.h to match winbase.h regarding LoadLibraryA/W dd44d893 crt: ucrt.mri: Use one shared mri file for all architectures 4f9a809e crt: Regenerate Makefile.in 05477ed8 crt: Rename longjmp.S to mingw_longjmp.S b983d26a crt: Regenerate Makefile.in 0d403d5d crt: Add a UCRT import library suitable for UWP use 118b0e8c crt: Regenerate Makefile.in f4a336f7 crt: Add a fallback _setmaxstdio for arm libmsvcrt-os.a f216044b crt: Regenerate Makefile.in 2ecdc067 widl: Update the relocatability patch to remove an unused variable 70b3baf5 widl: Remove the apparently unused getopt1.c source file 05cce8e8 widl: Regenerate Makefile.in bd529f4d crt: Update the arm32 ntdll def files based on a current arm32 ntdll.dll d44a2a03 crt: Move vDbgPrintEx functions from ntdllcrt to ntdll 9aa393d1 crt: Share ntdllcrt.def across architectures, provide it for arm64 35f50981 crt: Regenerate Makefile.in b60434b5 crt: Share ntdll.def across architectures, provide it for arm64 f9ef5b47 crt: Regenerate Makefile.in ceb3ac2f crt: Regenerate Makefile.in after 01e37e0c28 bf4836dc crt: Regenerate Makefile.in 82a46659 crt: Regenerate Makefile.in 9718ecee crt: Move .seh_handlerdata to the end of functions ebc06f3c crt: Silence GCC warnings about missing prototypes Marvin Scholz (1): 0a609c99 Fix msvcr120_app.def.in path Mateusz (4): a84fc015 Always define __USE_MINGW_ANSI_STDIO as 0 or 1 in _mingw.h 8565cdb7 stdio.h: set printf format attribute according to inttypes.h 38496499 timeb.h: declare _ftime32 function, define _ftime according to _USE_32BIT_TIME_T df15931c Add __mingw_access() that works the same for all msvcr*/ucrt libs Mateusz Brzostek (1): d66350ea move _fseeki64 and _ftelli64 functions from libmingwex to libmsvcrt Matheus Izvekov (3): a66e407e ddk/scsi.h: move type defs out of anonymous union 39717d7b ddk/scsi.h: remove pointer fields of CDB 73f932b7 guiddef: make __uuidof constexpr on c++17 and later Matthew Palermo (1): 68684a73 mbrtowc.c: Make mbsrtowcs comply with GNU libc when *dst=NULL Nikolay Sivov (11): 5c749438 Fix IDWriteTypography definition. 75bdd344 dwrite.h: Fix IDWriteLocalFontFileLoader definition. 7881d06f include: Add IDWriteTextLayout1 definition. fb39c974 include: Add remaining interface definitions from dwrite_1.h. af64e124 headers: Add DWRITE_VERTICAL_GLYPH_ORIENTATION definition. 2b9f5534 headers: Make dwrite_1.h C friendly. 13345699 include/d2d1.h: Fix enum identifier names from d2d1.h. 96916608 include/d2d1.h: Fix d2d1.h enum definitions with missing members. c034d588 include/d2d1.h: Add missing D2D1_DRAW_TEXT_OPTIONS members. 67708df9 headers: Cleanup some typedefs in mfidl.idl. 5f40a8ad headers: Move some symbols to correct locations, remove duplicated symbols in mfidl.idl. Noah Treuhaft (1): 76938aee stdio_s.h: Add L_tmpnam_s and TMP_MAX_S Ozkan Sezer (3): abccde3c ddraw.h updates: f86c5060 ddraw.h update based on Wine git commit 94db5c87195943957086f03b8a2f7fb3 12b5d134 change GetThemeSysFont() to accept a LOGFONTW* parameter (bug #862) Pali Rohár (4): dc3b2e2b crt: Fix snprintf() 2d28f1d2 genstubdll: Remove some erroneous aliases from example bfd33f6c Enable __USE_MINGW_ANSI_STDIO for C99 and C++11 when not using UCRT 8649bf9e _mingw.h: Do not check for _UCRT Pierre Lamot (2): 92ad4840 crt: add def for dcomp.dll and update dcomp.h af56acd2 dcomp.h: Work around C++ ABI differences. Richard Pospesel (1): 84b72df8 shobjidl.idl: added definition for FOS_SUPPORTSTREAMABLEITEMS to FILEOPENDIALOGOPTIONS enum Ruslan Garipov (12): 8b329a09 Add missed functions to retrieve pseudo-handles 2a93d842 Add missed OLE DB identifiers 6cf35bf4 Add missed OLE DB identifiers (addition) 79243349 {include,crt}: Add Microsoft OLE DB driver for SQL server 70e42d37 dwrite.h: Add missed parenthesis c0bc7713 d2d1_1.h: Add C declaration for ID2D1Factory1 56d4808e dwrite.h: Fix build in C mode 0c0da49f d2d1_1.h: Add C declaration for ID2D1DeviceContext 3cc762bf d2d1_1.h: Add C declaration for ID2D1Device 1bbc295f d2d1_1.h: Add C declaration for ID2D1Bitmap1 705a4899 d2d1_1.h: Add C declaration for ID2D1Multithread abeb540d dwrite_1.h: Fix build in C mode Sanketh Menda (1): 6ab1737e include/winbase.h: Remove mistaken `#ifdef` around `PROCESS_INFORMATION_CLASS` SquallATF (1): 8bba2a9f winpthreads: make winpthreads compatible with libcxx __attribute__((__require_constant_initialization__)) Stephan Ruloff (1): c10ffdf9 include/ntddcdrm.h: Add `IOCTL_CDROM_SET_SPEED` and `CDROM_SET_SPEED` Stephen Kitt (2): 8f1d602a Detect -lm in genlib 685aa5ce Drop the empty exception declaration from CheckError Steve Lhomme (104): 092d0ad0 windowsapp: add gamemode.dll APIs 380d62cb make some file APIs visible to Windows Store apps 551f5d57 OpenProcess is available for windows store on Windows 10 d642e215 fileapi: GetTempPath is available in desktop and app targets dfb9bef0 headers: add dxvahd.idl 191f402e headers: reorder dxvahd methods 4863bda8 headers: dxvahd API is only available on desktop 7b646dd2 headers: remove unknown PDXVAHD_STREAM_STATE_ASPECT_RATIO_DATA 8dd101de crt: use consistent format for the library name in api-ms-win-*.def files d344ff07 crt: reorder api-ms-win-*.def files in alphanumerical order 58971385 crt: remove GetFileVersionInfoSizeW/GetFileVersionInfoW from version-l1-1-1 ae275062 crt: add new found API entries api-ms-win-*.def 1013ae93 headers: move the C++ check for interlocked API ff2e4c60 Add the IApplicationData2 storage interface b57b0420 crt: add more DLLs to windowsapp aed900ea headers: hide most of the file version API in winstore builds 51fb0044 headers: hide CreateFileW/GetFileSize in winstore builds 531c9504 headers: allow FreeLibraryAndExitThread for winstore builds 2059ac24 headers: allow CryptReleaseContext for winstore builds 7d7dd4e3 headers: allow the ThreadPoolAPI in winstore builds da22d2f0 headers: allow some Memory API's in winstore builds d2a1c31d headers: allow Beep in winstore apps a6c13b93 headers: allow some CreateSemaphoreW/CreateWaitableTimerW for winstore builds 4d547f90 headers: add some Fiber API's allowed in winstore builds aa88352c headers: allow ReplaceFile in winstore builds 818afc73 headers: add directory and command line APIs to winstore builds 9adbc332 headers: add CopyFile to winstore builds 41f8c320 headers: add more Heap API's to winstore builds 81edce19 headers: add more file API's available in winstore builds d22b075e headers: add some tracing API's allowed in winstore builds 75b460e2 headers: allow GetUserDefaultLangID in winstore builds 8595dd85 headers: add some process/thread API's allowed in winstore builds a69b2fcc headers: add process API's allowed in winstore builds 0ea12423 headers: add some locale API's allowed in winstore builds 55554f98 headers: add CoIncrementMTAUsage/CoDecrementMTAUsage to winstore builds b0ce7aa8 headers: allow DebugBreak in winstore builds 4c76f080 headers: add SetErrorMode to winstore builds 3308c94f headers: forbid the use of WindowsInspectString in winstore builds f4ad72ff headers: allow RtlCaptureStackBackTrace and RtlVirtualUnwind in winstore builds 87dbbab4 headers: add some console API's to winstore builds 747b5111 headers: allow GetConsoleOutputCP in winstore builds 96624e52 headers: allow some sysinfoapi.h functions in winstore builds 903210e5 headers: allow some tracing API's in winstore builds 550b49a9 headers: add SetThreadInformation to winstore builds f50780a6 headers: allow SetFileCompletionNotificationModes in winstore builds e9bce614 headers: allow Get/SetThreadErrorMode in winstore builds d007f27a headers: add some communications device API's in winstore builds 11912fc5 headers: allow GetSystemTimes in winstore builds 37729ae9 headers: add CreateSemaphoreA/CreateSemaphoreExA in winstore builds 358bca68 headers: add GetNamedPipeHandleStateA/W to winstore builds 84285d60 headers: allow GetComputerName/SetVolumeLabel in winstore builds 36546af0 headers: allow GetSystemPowerStatus in winstore builds c2fd635f headers: add some security API's to winstore builds 61c74694 headers: add some namespace API's in winstore builds f4c20a52 headers: allow CommandLineToArgvW in winstore builds 6fd5d416 headers: allow IsWow64Process in winstore builds 9d3485bd headers: add more locale API's allowed in winstore builds ee0e91eb headers: allow GetAcceptLanguagesA/W in winstore builds cd4925a1 headers: add CM_Get_Device_Interface_List APIs in winstore builds 43c82664 headers: add some access control APIs in winstore builds 273b467c headers: add (Global)LocalAlloc APIs in winstore builds 6cc17cd4 headers: allow some process/thread affinity API's in winstore builds c1a1c87f headers: add some security identifier API's in winstore builds 8a72a37e headers: allow DeleteVolumeMountPointA in winstore builds f49017a5 headers: hide pseudo console API's in winstore builds b3ea1c75 headers: allow win8 path API in winstore builds f0d582c9 headers: allow some firmware APIs' in winstore builds 1bb16dd0 headers: crt: allow blocking some APIs in winstore builds 7c2e0a37 headers: crt: disable process APIs in winstore builds 6eb4652a headers: crt: disable cwait/_cwait in winstore builds 1eeb5242 headers: crt: forbid deprecated DLLs APIs in winstore builds 6bc5f5ca headers: crt: disable some character APIs in winstore builds 733ece1f headers: crt: disable _wctype global variable in winstore builds 44e8e712 headers: crt: hide some pipe API's in winstore builds 8c1ed669 headers: crt: disable some drive API's in winstore builds b50da295 headers: crt: move __stdio_common_v[sf]wprintf_p out of _WSTDIO_DEFINED a26992ee headers: add SetUnhandledExceptionFilter to winstore builds e3083354 headers: provide the WinMain prototype to winstore apps 9242af7a headers: crt: disable _resetstkoflw in UWP builds 4d7e6fb6 headers: crt: disable getpid in UWP builds 073a9b27 headers: crt: disable _getpid in UWP builds 8917aca0 crt: use GetEnvironmentVariableW in getopt d4ac8955 headers: allow CreateFileW/GetFileSize in winstore builds b8a6ea23 winstorecompat: provide GetUserName 90ed4ded winstorecompat: handle LoadLibraryA alongside LoadLibraryW b5da811f winstorecompat: add libwindowsappcompat to use with libwindowsapp 8f078a25 winstorecompat: Forward VirtualProtect to VirtualProtectFromApp on windows 10 16d5b3e3 winstorecompat: provide getpid 17eff275 crt: add some missing libraries now found in windowsapp d58069b1 winpthreads: simplify the USE_VEH_FOR_MSC_SETTHREADNAME check 01385c6a winpthreads: do not use the XXXExceptionHandler API in winstore builds 58f92b0f winpthreads: always return 0 in pthread_check() if the thread ended is 0 13c9e28c winpthreads: simplify the handle validity in pthread_check() 7cb70719 winpthreads: do not call GetHandleInformation in winstore build a32b6222 winpthreads: don't call SetThreadContext in winstore builds cc10545a winstorecompat: provide GetFileInformationByHandle 68d0e7d5 crt: remove WaitOnAddress/WakeByAddressXXX from kernel32 9464ea24 crt: remove winstorecompat duplicated functions from api-ms-win-security-cryptoapi 9e80f9b2 headers: fix defines for some allowed UWP API's 1445086e headers: add more values to AUDIO_STREAM_CATEGORY 1d112162 headers: add AUDCLNT_STREAMOPTIONS in audioclient.h/.idl d3e5d105 headers: add missing field in AudioClientProperties 01e37e0c headers: add ActivateAudioInterfaceAsync API's in mmdeviceapi 6ab6bf21 headers: add DEVINTERFACE_XXX GUIDs Tom Ritter (9): df24f3c7 Add Error Codes between 1460 and 1471 be6f9cbf specstrings.h: Add _Post_equals_last_error_ to specstrings.h. 40c6d3ae include: Add concurrencysal.h to the headers. 19e51f59 include: Move MEMORY_PRIORITY_* from winbase.h to processthreadsapi.h. Add a few PROCESSOR_ARCHITECTURE, SECURITY_CAPABILITY, and SECURITY_BUILTIN defines. ba74cffa Move MEMORY_PRIORITY_ defines outside a _WIN32_WINNT #if check to match Microsoft's definitions. 8db8dd5a libuuid.a: Include netlistmgr.h. 3cdd004f dcomp.h: Add some missing interfaces. b8e9cfb2 dcomptypes.h: Add some missing enums. cd4e5b71 shlwapi.h: Add missing ASSOCF flags. Tomáš Golembiovský (2): 5ace9333 include/cfgmgr32.h: add CM_Get_DevNode_PropertyW f62a8322 include/devpkey.h: add device property keys Zach Bacon (5): acd0bf61 crt: Implement IID_IAccessControl 61010644 crt: Add defines for IID_IEnumContextProps and IID_IContext in uuid.c 5a5a7c93 include: Add GUIDs for audio/image/media file summary information c8f9b0af crt: Add CLSID_DCOMAccessControl to uuid.c 5e2b398f crt: Add a few more UUID's for IHTMLOMWindowServices etc Zebediah Figura (16): a1f21b55 evntprov.h: Remove extraneous typedef. e8eac0de wmilib.h: Add function type declarations. a6deaa72 sal.h: Add more SAL directives. 877bea08 driverspecs.h: Add more SAL directives. 5a74c943 ntoskrnl: Provide memcmp() on i386. 19725c7c intsafe.h: Return the correct value on overflow. bf8b8cb4 ddk/ntintsafe.h: Add header. 290ddff1 ntstrsafe.h: Remove incomplete header. e80afb87 ntstrsafe.h: More fully implement. 76475834 crt: Correctly restore %edi on exit from __argtos(). 555bee80 sal.h: Add more SAL directives. 326560ce driverspecs.h: Add more SAL directives. 60affb06 wdm.h: Define KSYNCHRONIZE_ROUTINE. 2df3cfe2 wdm.h: Add some power framework definitions. 9c37f69e wdm.h: Define DMA_COMPLETION_STATUS. b1487f41 wdm.h: Add some EX_TIMER definitions. sezero (3): fb78a1cd dinput.h and dsound.h updates, 03d07ca1 dinput.h: updates from wine git commit a9bc8a3. 1b1dc620 dsound.h: updates based on wine git commits 8f1ec07, 9023374 and 3a17ee9. xnor (1): 330025c5 Wait on sema_b again to ensure pthread_cond_wait() functions atomically as required by POSIX. xtne6f (1): 240557aa include: Fix definition of VMR9AlphaBitmap Руслан Ижбулатов (3): 6c32da39 Round up when converting nanoseconds to milliseconds 52f2ce12 Ensure wait timeouts are respected e8a89573 Update GL headers to git-6f5d3d0 屈佳伟 (1): 09ca997c headers: add missing field "dwOwningPid" in struct _MIB_TCPROW2 --- mingw-w64-crt/misc/getopt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mingw-w64-crt/misc/getopt.c b/mingw-w64-crt/misc/getopt.c index ac1fda426e..ac7f9fe16d 100644 --- a/mingw-w64-crt/misc/getopt.c +++ b/mingw-w64-crt/misc/getopt.c @@ -345,7 +345,7 @@ getopt_internal(int nargc, char * const *nargv, const char *options, * optreset != 0 for GNU compatibility. */ if (posixly_correct == -1 || optreset != 0) - posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + posixly_correct = (GetEnvironmentVariableW(L"POSIXLY_CORRECT", NULL, 0) != 0); if (*options == '-') flags |= FLAG_ALLARGS; else if (posixly_correct || *options == '+') From 72e59ae6760c5afcc8978d3804dc5a52cfb1041e Mon Sep 17 00:00:00 2001 From: Chuck Atkins Date: Fri, 30 Oct 2020 11:41:35 -0400 Subject: [PATCH 05/17] Clean for nlohmann_json update --- .../nlohmann_json/CMakeLists.txt | 9 - .../src/single_include/nlohmann/json.hpp | 20412 ---------------- 2 files changed, 20421 deletions(-) delete mode 100644 thirdparty/nlohmann_json/nlohmann_json/CMakeLists.txt delete mode 100644 thirdparty/nlohmann_json/nlohmann_json/src/single_include/nlohmann/json.hpp diff --git a/thirdparty/nlohmann_json/nlohmann_json/CMakeLists.txt b/thirdparty/nlohmann_json/nlohmann_json/CMakeLists.txt deleted file mode 100644 index b3ed049b42..0000000000 --- a/thirdparty/nlohmann_json/nlohmann_json/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -add_library(nlohmann_json INTERFACE) -target_sources(nlohmann_json INTERFACE - $ -) -target_include_directories(nlohmann_json INTERFACE - $ -) -install(TARGETS nlohmann_json EXPORT adios2Exports) - diff --git a/thirdparty/nlohmann_json/nlohmann_json/src/single_include/nlohmann/json.hpp b/thirdparty/nlohmann_json/nlohmann_json/src/single_include/nlohmann/json.hpp deleted file mode 100644 index 1ab26d62f3..0000000000 --- a/thirdparty/nlohmann_json/nlohmann_json/src/single_include/nlohmann/json.hpp +++ /dev/null @@ -1,20412 +0,0 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.5.0 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -SPDX-License-Identifier: MIT -Copyright (c) 2013-2018 Niels Lohmann . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef NLOHMANN_JSON_HPP -#define NLOHMANN_JSON_HPP - -#define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 5 -#define NLOHMANN_JSON_VERSION_PATCH 0 - -#include // all_of, find, for_each -#include // assert -#include // and, not, or -#include // nullptr_t, ptrdiff_t, size_t -#include // hash, less -#include // initializer_list -#include // istream, ostream -#include // random_access_iterator_tag -#include // accumulate -#include // string, stoi, to_string -#include // declval, forward, move, pair, swap - -// #include -#ifndef NLOHMANN_JSON_FWD_HPP -#define NLOHMANN_JSON_FWD_HPP - -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; - -template class ObjectType = - std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer> -class basic_json; - -/*! -@brief JSON Pointer - -A JSON pointer defines a string syntax for identifying a specific value -within a JSON document. It can be used with functions `at` and -`operator[]`. Furthermore, JSON pointers are the base for JSON patches. - -@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - -@since version 2.0.0 -*/ -template -class json_pointer; - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; -} // namespace nlohmann - -#endif - -// #include - - -// This file contains all internal macro definitions -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them - -// exclude unsupported compilers -#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) - #if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -// allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) - #define JSON_THROW(exception) throw exception - #define JSON_TRY try - #define JSON_CATCH(exception) catch(exception) - #define JSON_INTERNAL_CATCH(exception) catch(exception) -#else - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) - #define JSON_INTERNAL_CATCH(exception) if(false) -#endif - -// override exception macros -#if defined(JSON_THROW_USER) - #undef JSON_THROW - #define JSON_THROW JSON_THROW_USER -#endif -#if defined(JSON_TRY_USER) - #undef JSON_TRY - #define JSON_TRY JSON_TRY_USER -#endif -#if defined(JSON_CATCH_USER) - #undef JSON_CATCH - #define JSON_CATCH JSON_CATCH_USER - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_CATCH_USER -#endif -#if defined(JSON_INTERNAL_CATCH_USER) - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER -#endif - -// manual branch prediction -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) - #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - #define JSON_LIKELY(x) x - #define JSON_UNLIKELY(x) x -#endif - -// C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 -#endif - -/*! -@brief macro to briefly define a mapping between an enum and JSON -@def NLOHMANN_JSON_SERIALIZE_ENUM -@since version 3.4.0 -*/ -#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ - template \ - inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [e](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.first == e; \ - }); \ - j = ((it != std::end(m)) ? it : std::begin(m))->second; \ - } \ - template \ - inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [j](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.second == j; \ - }); \ - e = ((it != std::end(m)) ? it : std::begin(m))->first; \ - } - -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - -// #include - - -#include // not -#include // size_t -#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type - -namespace nlohmann -{ -namespace detail -{ -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -template -using uncvref_t = typename std::remove_cv::type>::type; - -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -template -struct merge_and_renumber; - -template -struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; - -template -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; - -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; - -template -using index_sequence_for = make_index_sequence; - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; -} // namespace detail -} // namespace nlohmann - -// #include - - -#include // not -#include // numeric_limits -#include // false_type, is_constructible, is_integral, is_same, true_type -#include // declval - -// #include - -// #include - - -#include // random_access_iterator_tag - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template struct make_void -{ - using type = void; -}; -template using void_t = typename make_void::type; -} // namespace detail -} // namespace nlohmann - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template -struct iterator_types {}; - -template -struct iterator_types < - It, - void_t> -{ - using difference_type = typename It::difference_type; - using value_type = typename It::value_type; - using pointer = typename It::pointer; - using reference = typename It::reference; - using iterator_category = typename It::iterator_category; -}; - -// This is required as some compilers implement std::iterator_traits in a way that -// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. -template -struct iterator_traits -{ -}; - -template -struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> - : iterator_types -{ -}; - -template -struct iterator_traits::value>> -{ - using iterator_category = std::random_access_iterator_tag; - using value_type = T; - using difference_type = ptrdiff_t; - using pointer = T*; - using reference = T&; -}; -} -} - -// #include - -// #include - - -#include - -// #include - - -// http://en.cppreference.com/w/cpp/experimental/is_detected -namespace nlohmann -{ -namespace detail -{ -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - void operator=(nonesuch const&) = delete; -}; - -template class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; - -template class Op, class... Args> -struct detector>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op; -}; - -template